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/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 } options;
  46 
  47 extern gboolean stage0(pe_working_set_t * data_set);
  48 
  49 static GOptionEntry data_entries[] = {
  50     { "live-check", 'L', 0, G_OPTION_ARG_NONE,
  51       &options.use_live_cib, "Check the configuration used by the running cluster",
  52       NULL },
  53     { "xml-file", 'x', 0, G_OPTION_ARG_FILENAME,
  54       &options.xml_file, "Check the configuration in the named file",
  55       "FILE" },
  56     { "xml-pipe", 'p', 0, G_OPTION_ARG_NONE,
  57       &options.xml_stdin, "Check the configuration piped in via stdin",
  58       NULL },
  59     { "xml-text", 'X', 0, G_OPTION_ARG_STRING,
  60       &options.xml_string, "Check the configuration in the supplied string",
  61       "XML" },
  62 
  63     { NULL }
  64 };
  65 
  66 static GOptionEntry addl_entries[] = {
  67     { "save-xml", 'S', G_OPTION_FLAG_NONE, G_OPTION_ARG_FILENAME,
  68       &options.cib_save, "Save verified XML to named file (most useful with -L)",
  69       "FILE" },
  70 
  71     { NULL }
  72 };
  73 
  74 static pcmk__supported_format_t formats[] = {
  75     PCMK__SUPPORTED_FORMAT_NONE,
  76     PCMK__SUPPORTED_FORMAT_TEXT,
  77     PCMK__SUPPORTED_FORMAT_XML,
  78     { NULL, NULL, NULL }
  79 };
  80 
  81 static GOptionContext *
  82 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
     /* [previous][next][first][last][top][bottom][index][help] */
  83     GOptionContext *context = NULL;
  84 
  85     const char *description = "Examples:\n\n"
  86                               "Check the consistency of the configuration in the running cluster:\n\n"
  87                               "\tcrm_verify --live-check\n\n"
  88                               "Check the consistency of the configuration in a given file and "
  89                               "produce verbose output:\n\n"
  90                               "\tcrm_verify --xml-file file.xml --verbose\n\n";
  91 
  92     context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
  93     g_option_context_set_description(context, description);
  94 
  95     pcmk__add_arg_group(context, "data", "Data sources:",
  96                         "Show data options", data_entries);
  97     pcmk__add_arg_group(context, "additional", "Additional options:",
  98                         "Show additional options", addl_entries);
  99 
 100     return context;
 101 }
 102 
 103 int
 104 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 105 {
 106     xmlNode *cib_object = NULL;
 107     xmlNode *status = NULL;
 108 
 109     pe_working_set_t *data_set = NULL;
 110     cib_t *cib_conn = 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         cib_conn = cib_new();
 152         rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
 153         rc = pcmk_legacy2rc(rc);
 154     }
 155 
 156     if (options.use_live_cib) {
 157         if (rc == pcmk_rc_ok) {
 158             int options = cib_scope_local | cib_sync_call;
 159 
 160             crm_info("Reading XML from: live cluster");
 161             rc = cib_conn->cmds->query(cib_conn, NULL, &cib_object, options);
 162             rc = pcmk_legacy2rc(rc);
 163         }
 164 
 165         if (rc != pcmk_rc_ok) {
 166             g_set_error(&error, PCMK__RC_ERROR, rc, "Live CIB query failed: %s", pcmk_rc_str(rc));
 167             goto done;
 168         }
 169         if (cib_object == NULL) {
 170             rc = ENOMSG;
 171             g_set_error(&error, PCMK__RC_ERROR, rc, "Live CIB query failed: empty result");
 172             goto done;
 173         }
 174 
 175     } else if (options.xml_file != NULL) {
 176         cib_object = filename2xml(options.xml_file);
 177         if (cib_object == NULL) {
 178             rc = ENODATA;
 179             g_set_error(&error, PCMK__RC_ERROR, rc, "Couldn't parse input file: %s", options.xml_file);
 180             goto done;
 181         }
 182 
 183     } else if (options.xml_string != NULL) {
 184         cib_object = string2xml(options.xml_string);
 185         if (cib_object == NULL) {
 186             rc = ENODATA;
 187             g_set_error(&error, PCMK__RC_ERROR, rc, "Couldn't parse input string: %s", options.xml_string);
 188             goto done;
 189         }
 190     } else if (options.xml_stdin) {
 191         cib_object = stdin2xml();
 192         if (cib_object == NULL) {
 193             rc = ENODATA;
 194             g_set_error(&error, PCMK__RC_ERROR, rc, "Couldn't parse input from STDIN.");
 195             goto done;
 196         }
 197 
 198     } else {
 199         rc = ENODATA;
 200         g_set_error(&error, PCMK__RC_ERROR, rc,
 201                     "No configuration source specified.  Use --help for usage information.");
 202         goto done;
 203     }
 204 
 205     xml_tag = crm_element_name(cib_object);
 206     if (!pcmk__str_eq(xml_tag, XML_TAG_CIB, pcmk__str_casei)) {
 207         rc = EBADMSG;
 208         g_set_error(&error, PCMK__RC_ERROR, rc,
 209                     "This tool can only check complete configurations (i.e. those starting with <cib>).");
 210         goto done;
 211     }
 212 
 213     if (options.cib_save != NULL) {
 214         write_xml_file(cib_object, options.cib_save, FALSE);
 215     }
 216 
 217     status = get_object_root(XML_CIB_TAG_STATUS, cib_object);
 218     if (status == NULL) {
 219         create_xml_node(cib_object, XML_CIB_TAG_STATUS);
 220     }
 221 
 222     if (validate_xml(cib_object, NULL, FALSE) == FALSE) {
 223         pcmk__config_err("CIB did not pass schema validation");
 224         free_xml(cib_object);
 225         cib_object = NULL;
 226 
 227     } else if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
 228         crm_config_error = TRUE;
 229         free_xml(cib_object);
 230         cib_object = NULL;
 231         out->err(out, "The cluster will NOT be able to use this configuration.\n"
 232                  "Please manually update the configuration to conform to the %s syntax.",
 233                  xml_latest_schema());
 234     }
 235 
 236     data_set = pe_new_working_set();
 237     if (data_set == NULL) {
 238         rc = errno;
 239         crm_perror(LOG_CRIT, "Unable to allocate working set");
 240         goto done;
 241     }
 242     pe__set_working_set_flags(data_set, pe_flag_no_counts|pe_flag_no_compat);
 243     data_set->priv = out;
 244 
 245     if (cib_object == NULL) {
 246     } else if (status != NULL || options.use_live_cib) {
 247         /* live queries will always have a status section and can do a full simulation */
 248         pcmk__schedule_actions(data_set, cib_object, NULL);
 249 
 250     } else {
 251         data_set->now = crm_time_new(NULL);
 252         data_set->input = cib_object;
 253         stage0(data_set);
 254     }
 255     pe_free_working_set(data_set);
 256 
 257     if (crm_config_error) {
 258         rc = pcmk_rc_schema_validation;
 259 
 260         if (args->verbosity > 0) {
 261             g_set_error(&error, PCMK__RC_ERROR, rc,
 262                         "Errors found during check: config not valid");
 263         } else {
 264             g_set_error(&error, PCMK__RC_ERROR, rc,
 265                         "Errors found during check: config not valid\n-V may provide more details");
 266         }
 267 
 268     } else if (crm_config_warning) {
 269         rc = pcmk_rc_schema_validation;
 270 
 271         if (args->verbosity > 0) {
 272             g_set_error(&error, PCMK__RC_ERROR, rc,
 273                         "Warnings found during check: config may not be valid");
 274         } else {
 275             g_set_error(&error, PCMK__RC_ERROR, rc,
 276                         "Warnings found during check: config may not be valid\n-V may provide more details");
 277         }
 278     }
 279 
 280     if (options.use_live_cib && cib_conn) {
 281         cib_conn->cmds->signoff(cib_conn);
 282         cib_delete(cib_conn);
 283     }
 284 
 285   done:
 286     g_strfreev(processed_args);
 287     pcmk__free_arg_context(context);
 288     free(options.cib_save);
 289     free(options.xml_file);
 290     free(options.xml_string);
 291 
 292     if (exit_code == CRM_EX_OK) {
 293         exit_code = pcmk_rc2exitc(rc);
 294     }
 295 
 296     pcmk__output_and_clear_error(error, NULL);
 297 
 298     if (out != NULL) {
 299         out->finish(out, exit_code, true, NULL);
 300         pcmk__output_free(out);
 301     }
 302 
 303     crm_exit(exit_code);
 304 }

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