root/tools/crm_verify.c

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

DEFINITIONS

This source file includes following definitions.
  1. main

   1 /*
   2  * Copyright 2004-2020 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 
  13 #include <stdio.h>
  14 #include <sys/types.h>
  15 #include <unistd.h>
  16 
  17 #include <stdlib.h>
  18 #include <errno.h>
  19 #include <fcntl.h>
  20 #include <libgen.h>
  21 #include <glib.h>
  22 
  23 #include <crm/common/xml.h>
  24 #include <crm/common/util.h>
  25 #include <crm/msg_xml.h>
  26 #include <crm/cib.h>
  27 #include <crm/pengine/status.h>
  28 #include <pacemaker-internal.h>
  29 
  30 gboolean USE_LIVE_CIB = FALSE;
  31 char *cib_save = NULL;
  32 extern gboolean stage0(pe_working_set_t * data_set);
  33 
  34 static pcmk__cli_option_t long_options[] = {
  35     // long option, argument type, storage, short option, description, flags
  36     {
  37         "help", no_argument, NULL, '?',
  38         "\tThis text", pcmk__option_default
  39     },
  40     {
  41         "version", no_argument, NULL, '$',
  42         "\tVersion information", pcmk__option_default
  43     },
  44     {
  45         "verbose", no_argument, NULL, 'V',
  46         "\tSpecify multiple times to increase debug output\n",
  47         pcmk__option_default
  48     },
  49     {
  50         "-spacer-", no_argument, NULL, '-',
  51         "\nData sources:", pcmk__option_default
  52     },
  53     {
  54         "live-check", no_argument, NULL, 'L',
  55         "Check the configuration used by the running cluster\n",
  56         pcmk__option_default
  57     },
  58     {
  59         "xml-file", required_argument, NULL, 'x',
  60         "Check the configuration in the named file", pcmk__option_default
  61     },
  62     {
  63         "xml-text", required_argument, NULL, 'X',
  64         "Check the configuration in the supplied string", pcmk__option_default
  65     },
  66     {
  67         "xml-pipe", no_argument, NULL, 'p',
  68         "Check the configuration piped in via stdin", pcmk__option_default
  69     },
  70     {
  71         "-spacer-", no_argument, NULL, '-',
  72         "\nAdditional Options:", pcmk__option_default
  73     },
  74     {
  75         "save-xml", required_argument, 0, 'S',
  76         "Save verified XML to named file (most useful with -L)",
  77         pcmk__option_default
  78     },
  79     {
  80         "-spacer-", no_argument, NULL, '-',
  81         "\nExamples:", pcmk__option_paragraph
  82     },
  83     {
  84         "-spacer-", no_argument, NULL, '-',
  85         "Check the consistency of the configuration in the running cluster:",
  86         pcmk__option_paragraph
  87     },
  88     {
  89         "-spacer-", no_argument, NULL, '-',
  90         " crm_verify --live-check", pcmk__option_example
  91     },
  92     {
  93         "-spacer-", no_argument, NULL, '-',
  94         "Check the consistency of the configuration in a given file and "
  95             "produce verbose output:",
  96         pcmk__option_paragraph
  97     },
  98     {
  99         "-spacer-", no_argument, NULL, '-',
 100         " crm_verify --xml-file file.xml --verbose", pcmk__option_example
 101     },
 102     {0, 0, 0, 0}
 103 };
 104 
 105 int
 106 main(int argc, char **argv)
     /* [previous][next][first][last][top][bottom][index][help] */
 107 {
 108     xmlNode *cib_object = NULL;
 109     xmlNode *status = NULL;
 110     int argerr = 0;
 111     int flag;
 112     int option_index = 0;
 113 
 114     pe_working_set_t *data_set = NULL;
 115     cib_t *cib_conn = NULL;
 116     int rc = pcmk_ok;
 117 
 118     bool verbose = FALSE;
 119     gboolean xml_stdin = FALSE;
 120     const char *xml_tag = NULL;
 121     const char *xml_file = NULL;
 122     const char *xml_string = NULL;
 123 
 124     crm_log_cli_init("crm_verify");
 125     pcmk__set_cli_options(NULL, "[options]", long_options,
 126                           "check a Pacemaker configuration for errors\n\n"
 127                           "Check the well-formedness of a complete Pacemaker "
 128                           "XML configuration,\nits conformance to the "
 129                           "configured schema, and the presence of common\n"
 130                           "misconfigurations. Problems reported as errors "
 131                           "must be fixed before the\ncluster will work "
 132                           "properly. It is left to the administrator to decide"
 133                           "\nwhether to fix problems reported as warnings.");
 134 
 135     while (1) {
 136         flag = pcmk__next_cli_option(argc, argv, &option_index, NULL);
 137         if (flag == -1)
 138             break;
 139 
 140         switch (flag) {
 141             case 'X':
 142                 crm_trace("Option %c => %s", flag, optarg);
 143                 xml_string = optarg;
 144                 break;
 145             case 'x':
 146                 crm_trace("Option %c => %s", flag, optarg);
 147                 xml_file = optarg;
 148                 break;
 149             case 'p':
 150                 xml_stdin = TRUE;
 151                 break;
 152             case 'S':
 153                 cib_save = optarg;
 154                 break;
 155             case 'V':
 156                 verbose = TRUE;
 157                 crm_bump_log_level(argc, argv);
 158                 break;
 159             case 'L':
 160                 USE_LIVE_CIB = TRUE;
 161                 break;
 162             case '$':
 163             case '?':
 164                 pcmk__cli_help(flag, CRM_EX_OK);
 165                 break;
 166             default:
 167                 fprintf(stderr, "Option -%c is not yet supported\n", flag);
 168                 ++argerr;
 169                 break;
 170         }
 171     }
 172 
 173     if (optind < argc) {
 174         printf("non-option ARGV-elements: ");
 175         while (optind < argc) {
 176             printf("%s ", argv[optind++]);
 177         }
 178         printf("\n");
 179     }
 180 
 181     if (optind > argc) {
 182         ++argerr;
 183     }
 184 
 185     if (argerr) {
 186         crm_err("%d errors in option parsing", argerr);
 187         pcmk__cli_help(flag, CRM_EX_USAGE);
 188     }
 189 
 190     crm_info("=#=#=#=#= Getting XML =#=#=#=#=");
 191 
 192     if (USE_LIVE_CIB) {
 193         cib_conn = cib_new();
 194         rc = cib_conn->cmds->signon(cib_conn, crm_system_name, cib_command);
 195     }
 196 
 197     if (USE_LIVE_CIB) {
 198         if (rc == pcmk_ok) {
 199             int options = cib_scope_local | cib_sync_call;
 200 
 201             crm_info("Reading XML from: live cluster");
 202             rc = cib_conn->cmds->query(cib_conn, NULL, &cib_object, options);
 203         }
 204 
 205         if (rc != pcmk_ok) {
 206             fprintf(stderr, "Live CIB query failed: %s\n", pcmk_strerror(rc));
 207             goto done;
 208         }
 209         if (cib_object == NULL) {
 210             fprintf(stderr, "Live CIB query failed: empty result\n");
 211             rc = -ENOMSG;
 212             goto done;
 213         }
 214 
 215     } else if (xml_file != NULL) {
 216         cib_object = filename2xml(xml_file);
 217         if (cib_object == NULL) {
 218             fprintf(stderr, "Couldn't parse input file: %s\n", xml_file);
 219             rc = -ENODATA;
 220             goto done;
 221         }
 222 
 223     } else if (xml_string != NULL) {
 224         cib_object = string2xml(xml_string);
 225         if (cib_object == NULL) {
 226             fprintf(stderr, "Couldn't parse input string: %s\n", xml_string);
 227             rc = -ENODATA;
 228             goto done;
 229         }
 230     } else if (xml_stdin) {
 231         cib_object = stdin2xml();
 232         if (cib_object == NULL) {
 233             fprintf(stderr, "Couldn't parse input from STDIN.\n");
 234             rc = -ENODATA;
 235             goto done;
 236         }
 237 
 238     } else {
 239         fprintf(stderr, "No configuration source specified."
 240                 "  Use --help for usage information.\n");
 241         rc = -ENODATA;
 242         goto done;
 243     }
 244 
 245     xml_tag = crm_element_name(cib_object);
 246     if (!pcmk__str_eq(xml_tag, XML_TAG_CIB, pcmk__str_casei)) {
 247         fprintf(stderr,
 248                 "This tool can only check complete configurations (i.e. those starting with <cib>).\n");
 249         rc = -EBADMSG;
 250         goto done;
 251     }
 252 
 253     if (cib_save != NULL) {
 254         write_xml_file(cib_object, cib_save, FALSE);
 255     }
 256 
 257     status = get_object_root(XML_CIB_TAG_STATUS, cib_object);
 258     if (status == NULL) {
 259         create_xml_node(cib_object, XML_CIB_TAG_STATUS);
 260     }
 261 
 262     if (validate_xml(cib_object, NULL, FALSE) == FALSE) {
 263         pcmk__config_err("CIB did not pass schema validation");
 264         free_xml(cib_object);
 265         cib_object = NULL;
 266 
 267     } else if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) {
 268         pcmk__config_error = true;
 269         free_xml(cib_object);
 270         cib_object = NULL;
 271         fprintf(stderr, "The cluster will NOT be able to use this configuration.\n");
 272         fprintf(stderr, "Please manually update the configuration to conform to the %s syntax.\n",
 273                 xml_latest_schema());
 274     }
 275 
 276     data_set = pe_new_working_set();
 277     if (data_set == NULL) {
 278         rc = -errno;
 279         crm_perror(LOG_CRIT, "Unable to allocate working set");
 280         goto done;
 281     }
 282     pe__set_working_set_flags(data_set, pe_flag_no_counts|pe_flag_no_compat);
 283 
 284     if (cib_object == NULL) {
 285     } else if (status != NULL || USE_LIVE_CIB) {
 286         /* live queries will always have a status section and can do a full simulation */
 287         pcmk__schedule_actions(data_set, cib_object, NULL);
 288 
 289     } else {
 290         data_set->now = crm_time_new(NULL);
 291         data_set->input = cib_object;
 292         stage0(data_set);
 293     }
 294     pe_free_working_set(data_set);
 295 
 296     if (pcmk__config_error) {
 297         fprintf(stderr, "Errors found during check: config not valid\n");
 298         if (verbose == FALSE) {
 299             fprintf(stderr, "  -V may provide more details\n");
 300         }
 301         rc = -pcmk_err_schema_validation;
 302 
 303     } else if (pcmk__config_warning) {
 304         fprintf(stderr, "Warnings found during check: config may not be valid\n");
 305         if (verbose == FALSE) {
 306             fprintf(stderr, "  Use -V -V for more details\n");
 307         }
 308         rc = -pcmk_err_schema_validation;
 309     }
 310 
 311     if (USE_LIVE_CIB && cib_conn) {
 312         cib_conn->cmds->signoff(cib_conn);
 313         cib_delete(cib_conn);
 314     }
 315 
 316   done:
 317     crm_exit(crm_errno2exit(rc));
 318 }

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