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         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     int rc = pcmk_rc_ok;
  53     xmlNode *status = NULL;
  54     xmlNode *cib_object_copy = NULL;
  55 
  56     pcmk__assert(cib_object != NULL);
  57 
  58     /* Without the CIB element, we can't get a schema to validate against, so
  59      * report that separately from validation
  60      */
  61     if (!pcmk__xe_is(*cib_object, PCMK_XE_CIB)) {
  62         out->err(out,
  63                  "Input is not a CIB (outermost element is %s not "
  64                  PCMK_XE_CIB ")",
  65                  pcmk__s((const char *) (*cib_object)->name, "unrecognizable"));
  66         rc = pcmk_rc_schema_validation;
  67         goto verify_done;
  68     }
  69 
  70     status = pcmk_find_cib_element(*cib_object, PCMK_XE_STATUS);
  71     if (status == NULL) {
  72         pcmk__xe_create(*cib_object, PCMK_XE_STATUS);
  73     }
  74 
  75     if (!pcmk__validate_xml(*cib_object, NULL,
  76                             (xmlRelaxNGValidityErrorFunc) out->err, out)) {
  77         pcmk__config_has_error = true;
  78         rc = pcmk_rc_schema_validation;
  79         goto verify_done;
  80     }
  81 
  82     rc = pcmk__update_configured_schema(cib_object, false);
  83     if (rc != pcmk_rc_ok) {
  84         pcmk__config_has_error = true;
  85         out->err(out, "The cluster will NOT be able to use this configuration.\n"
  86                  "Please manually update the configuration to conform to the %s syntax.",
  87                  pcmk__highest_schema_name());
  88         goto verify_done;
  89     }
  90 
  91     /* Process the configuration to set pcmk__config_has_error and
  92      * pcmk__config_has_warning.
  93      *
  94      * @TODO Some parts of the configuration are unpacked only when needed (for
  95      * example, action configuration), so we aren't necessarily checking those.
  96      */
  97     if (*cib_object != NULL) {
  98         unsigned long long flags = pcmk__sched_no_counts;
  99 
 100         if (status == NULL) {
 101             // No status available, so do minimal checks
 102             flags |= pcmk__sched_validate_only;
 103         }
 104         cib_object_copy = pcmk__xml_copy(NULL, *cib_object);
 105 
 106         /* The scheduler takes ownership of the XML object and potentially
 107          * frees it later. We want the caller of pcmk__verify to retain
 108          * ownership of the passed-in XML object, hence we pass in a copy
 109          * to the scheduler.
 110          */
 111         pcmk__schedule_actions(cib_object_copy, flags, scheduler);
 112     }
 113 
 114 verify_done:
 115     if (pcmk__config_has_error) {
 116         rc = pcmk_rc_schema_validation;
 117         pcmk__config_err("CIB did not pass schema validation");
 118     } else if (pcmk__config_has_warning) {
 119         rc = pcmk_rc_schema_validation;
 120     }
 121     return rc;
 122 }
 123 
 124 int
 125 pcmk_verify(xmlNodePtr *xml, const char *cib_source)
     /* [previous][next][first][last][top][bottom][index][help] */
 126 {
 127     pcmk_scheduler_t *scheduler = NULL;
 128     pcmk__output_t *out = NULL;
 129     int rc = pcmk_rc_ok;
 130 
 131     xmlNode *cib_object = NULL;
 132 
 133     rc = pcmk__xml_output_new(&out, xml);
 134     if (rc != pcmk_rc_ok) {
 135         return rc;
 136     }
 137 
 138     pe__register_messages(out);
 139     pcmk__register_lib_messages(out);
 140 
 141     rc = pcmk__parse_cib(out, cib_source, &cib_object);
 142     if (rc != pcmk_rc_ok) {
 143         out->err(out, "Verification failed: %s", pcmk_rc_str(rc));
 144         goto done;
 145     }
 146 
 147     scheduler = pe_new_working_set();
 148     if (scheduler == NULL) {
 149         rc = errno;
 150         out->err(out, "Couldn't allocate scheduler data: %s", pcmk_rc_str(rc));
 151         goto done;
 152     }
 153 
 154     scheduler->priv->out = out;
 155     rc = pcmk__verify(scheduler, out, &cib_object);
 156 
 157 done:
 158     pe_free_working_set(scheduler);
 159     pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
 160     pcmk__xml_free(cib_object);
 161     return rc;
 162 }

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