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-2025 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         return cib__signon_query(out, NULL, cib_object);
  33     }
  34 
  35     while (isspace(*first)) {
  36         first++;
  37     }
  38 
  39     if (*first == '<') {
  40         *cib_object = pcmk__xml_parse(cib_source);
  41     } else {
  42         *cib_object = pcmk__xml_read(cib_source);
  43     }
  44 
  45     return (*cib_object == NULL)? pcmk_rc_unpack_error : pcmk_rc_ok;
  46 }
  47 
  48 int
  49 pcmk__verify(pcmk_scheduler_t *scheduler, pcmk__output_t *out,
     /* [previous][next][first][last][top][bottom][index][help] */
  50              xmlNode **cib_object)
  51 {
  52     /* @TODO The scheduler argument is needed only for pcmk__config_has_error
  53      * and pcmk__config_has_warning. When we reset the scheduler, we reset those
  54      * global variables. Otherwise, we could drop the argument and create our
  55      * own scheduler object locally. Then we could be confident that it has no
  56      * relevant state.
  57      *
  58      * We should improve this, possibly with an "enum pcmk__fail_type" pointer
  59      * argument or similar.
  60      */
  61     int rc = pcmk_rc_ok;
  62     xmlNode *status = NULL;
  63 
  64     pcmk__assert((cib_object != NULL) && (*cib_object != NULL));
  65 
  66     /* Without the CIB element, we can't get a schema to validate against, so
  67      * report that separately from validation
  68      */
  69     if (!pcmk__xe_is(*cib_object, PCMK_XE_CIB)) {
  70         out->err(out,
  71                  "Input is not a CIB (outermost element is %s not "
  72                  PCMK_XE_CIB ")",
  73                  pcmk__s((const char *) (*cib_object)->name, "unrecognizable"));
  74         rc = pcmk_rc_schema_validation;
  75         goto verify_done;
  76     }
  77 
  78     status = pcmk_find_cib_element(*cib_object, PCMK_XE_STATUS);
  79     if (status == NULL) {
  80         pcmk__xe_create(*cib_object, PCMK_XE_STATUS);
  81     }
  82 
  83     if (!pcmk__validate_xml(*cib_object, NULL,
  84                             (xmlRelaxNGValidityErrorFunc) out->err, out)) {
  85         pcmk__config_has_error = true;
  86         rc = pcmk_rc_schema_validation;
  87         goto verify_done;
  88     }
  89 
  90     rc = pcmk__update_configured_schema(cib_object, false);
  91     if (rc != pcmk_rc_ok) {
  92         pcmk__config_has_error = true;
  93         out->err(out, "The cluster will NOT be able to use this configuration.\n"
  94                  "Please manually update the configuration to conform to the %s syntax.",
  95                  pcmk__highest_schema_name());
  96         goto verify_done;
  97     }
  98 
  99     /* Process the configuration to set pcmk__config_has_error and
 100      * pcmk__config_has_warning.
 101      *
 102      * @TODO Some parts of the configuration are unpacked only when needed (for
 103      * example, action configuration), so we aren't necessarily checking those.
 104      */
 105     if (*cib_object != NULL) {
 106         scheduler->input = *cib_object;
 107 
 108         pcmk__set_scheduler_flags(scheduler, pcmk__sched_no_counts);
 109         if (status == NULL) {
 110             // No status available, so do minimal checks
 111             pcmk__set_scheduler_flags(scheduler, pcmk__sched_validate_only);
 112         }
 113         pcmk__schedule_actions(scheduler);
 114 
 115         scheduler->input = NULL;
 116     }
 117 
 118 verify_done:
 119     if (pcmk__config_has_error) {
 120         rc = pcmk_rc_schema_validation;
 121         pcmk__config_err("CIB did not pass schema validation");
 122     } else if (pcmk__config_has_warning) {
 123         rc = pcmk_rc_schema_validation;
 124     }
 125     return rc;
 126 }
 127 
 128 int
 129 pcmk_verify(xmlNodePtr *xml, const char *cib_source)
     /* [previous][next][first][last][top][bottom][index][help] */
 130 {
 131     pcmk_scheduler_t *scheduler = NULL;
 132     pcmk__output_t *out = NULL;
 133     int rc = pcmk_rc_ok;
 134 
 135     xmlNode *cib_object = NULL;
 136 
 137     rc = pcmk__xml_output_new(&out, xml);
 138     if (rc != pcmk_rc_ok) {
 139         return rc;
 140     }
 141 
 142     pe__register_messages(out);
 143     pcmk__register_lib_messages(out);
 144 
 145     rc = pcmk__parse_cib(out, cib_source, &cib_object);
 146     if (rc != pcmk_rc_ok) {
 147         out->err(out, "Verification failed: %s", pcmk_rc_str(rc));
 148         goto done;
 149     }
 150 
 151     scheduler = pcmk_new_scheduler();
 152     if (scheduler == NULL) {
 153         rc = errno;
 154         out->err(out, "Couldn't allocate scheduler data: %s", pcmk_rc_str(rc));
 155         goto done;
 156     }
 157 
 158     scheduler->priv->out = out;
 159     rc = pcmk__verify(scheduler, out, &cib_object);
 160 
 161 done:
 162     pcmk_free_scheduler(scheduler);
 163     pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
 164     pcmk__xml_free(cib_object);
 165     return rc;
 166 }

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