root/lib/pacemaker/pcmk_verify.c

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

DEFINITIONS

This source file includes following definitions.
  1. pcmk__parse_cib
  2. pcmk__verify
  3. pcmk_verify

   1 /*
   2  * Copyright 2023-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 Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 #include <crm/cib/internal.h>
  12 #include <crm/common/output.h>
  13 #include <crm/common/results.h>
  14 #include <crm/common/scheduler.h>
  15 #include <pacemaker-internal.h>
  16 #include <pacemaker.h>
  17 
  18 #include <stdint.h>
  19 #include <sys/types.h>
  20 #include <sys/stat.h>
  21 #include <unistd.h>
  22 
  23 #include "libpacemaker_private.h"
  24 
  25 int
  26 pcmk__parse_cib(pcmk__output_t *out, const char *cib_source, xmlNodePtr *cib_object)
     /* [previous][next][first][last][top][bottom][index][help] */
  27 {
  28     // @COMPAT Take an enum for cib_source instead of trying to figure it out?
  29     const char *first = cib_source;
  30 
  31     if (cib_source == NULL) {
  32         crm_info("Reading XML from: live cluster");
  33         return cib__signon_query(out, NULL, cib_object);
  34     }
  35 
  36     while (isspace(*first)) {
  37         first++;
  38     }
  39 
  40     if (*first == '<') {
  41         *cib_object = pcmk__xml_parse(cib_source);
  42     } else {
  43         *cib_object = pcmk__xml_read(cib_source);
  44     }
  45 
  46     return (*cib_object == NULL)? ENODATA : pcmk_rc_ok;
  47 }
  48 
  49 int
  50 pcmk__verify(pcmk_scheduler_t *scheduler, pcmk__output_t *out,
     /* [previous][next][first][last][top][bottom][index][help] */
  51              xmlNode **cib_object)
  52 {
  53     int rc = pcmk_rc_ok;
  54     xmlNode *status = NULL;
  55     xmlNode *cib_object_copy = NULL;
  56 
  57     CRM_ASSERT(cib_object != NULL);
  58 
  59     if (!pcmk__xe_is(*cib_object, PCMK_XE_CIB)) {
  60         rc = EBADMSG;
  61         out->err(out, "This tool can only check complete configurations (i.e. those starting with <cib>).");
  62         goto verify_done;
  63     }
  64 
  65     status = pcmk_find_cib_element(*cib_object, PCMK_XE_STATUS);
  66     if (status == NULL) {
  67         pcmk__xe_create(*cib_object, PCMK_XE_STATUS);
  68     }
  69 
  70     if (!pcmk__validate_xml(*cib_object, NULL,
  71                             (xmlRelaxNGValidityErrorFunc) out->err, out)) {
  72         crm_config_error = TRUE;
  73         rc = pcmk_rc_schema_validation;
  74         goto verify_done;
  75     }
  76 
  77     rc = pcmk__update_configured_schema(cib_object, false);
  78     if (rc != pcmk_rc_ok) {
  79         crm_config_error = TRUE;
  80         out->err(out, "The cluster will NOT be able to use this configuration.\n"
  81                  "Please manually update the configuration to conform to the %s syntax.",
  82                  pcmk__highest_schema_name());
  83         goto verify_done;
  84     }
  85 
  86     /* Process the configuration to set crm_config_error/crm_config_warning.
  87      *
  88      * @TODO Some parts of the configuration are unpacked only when needed (for
  89      * example, action configuration), so we aren't necessarily checking those.
  90      */
  91     if (*cib_object != NULL) {
  92         unsigned long long flags = pcmk_sched_no_counts|pcmk_sched_no_compat;
  93 
  94         if (status == NULL) {
  95             // No status available, so do minimal checks
  96             flags |= pcmk_sched_validate_only;
  97         }
  98         cib_object_copy = pcmk__xml_copy(NULL, *cib_object);
  99 
 100         /* The scheduler takes ownership of the XML object and potentially
 101          * frees it later. We want the caller of pcmk__verify to retain
 102          * ownership of the passed-in XML object, hence we pass in a copy
 103          * to the scheduler.
 104          */ 
 105         pcmk__schedule_actions(cib_object_copy, flags, scheduler);
 106     }
 107 
 108 verify_done:
 109     if (crm_config_error) {
 110         rc = pcmk_rc_schema_validation;
 111         pcmk__config_err("CIB did not pass schema validation");
 112     } else if (crm_config_warning) {
 113         rc = pcmk_rc_schema_validation;
 114     }
 115     return rc;
 116 }
 117 
 118 int
 119 pcmk_verify(xmlNodePtr *xml, const char *cib_source)
     /* [previous][next][first][last][top][bottom][index][help] */
 120 {
 121     pcmk_scheduler_t *scheduler = NULL;
 122     pcmk__output_t *out = NULL;
 123     int rc = pcmk_rc_ok;
 124 
 125     xmlNode *cib_object = NULL;
 126 
 127     rc = pcmk__xml_output_new(&out, xml);
 128     if (rc != pcmk_rc_ok) {
 129         return rc;
 130     }
 131 
 132     pe__register_messages(out);
 133     pcmk__register_lib_messages(out);
 134 
 135     rc = pcmk__parse_cib(out, cib_source, &cib_object);
 136     if (rc != pcmk_rc_ok) {
 137         out->err(out, "Couldn't parse input");
 138         goto done;
 139     }
 140 
 141     scheduler = pe_new_working_set();
 142     if (scheduler == NULL) {
 143         rc = errno;
 144         out->err(out, "Couldn't allocate scheduler data: %s", pcmk_rc_str(rc));
 145         goto done;
 146     }
 147 
 148     scheduler->priv = out;
 149     rc = pcmk__verify(scheduler, out, &cib_object);
 150 
 151 done:
 152     pe_free_working_set(scheduler);
 153     pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
 154     free_xml(cib_object);
 155     return rc;
 156 }

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