pacemaker  3.0.0-d8340737c4
Scalable High-Availability cluster resource manager
pcmk_verify.c
Go to the documentation of this file.
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)
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
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"));
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)) {
79  goto verify_done;
80  }
81 
82  rc = pcmk__update_configured_schema(cib_object, false);
83  if (rc != pcmk_rc_ok) {
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.",
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
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:
117  pcmk__config_err("CIB did not pass schema validation");
118  } else if (pcmk__config_has_warning) {
120  }
121  return rc;
122 }
123 
124 int
125 pcmk_verify(xmlNodePtr *xml, const char *cib_source)
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 
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 
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:
159  pcmk__xml_output_finish(out, pcmk_rc2exitc(rc), xml);
160  pcmk__xml_free(cib_object);
161  return rc;
162 }
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:805
Control output from tools.
#define PCMK_XE_CIB
Definition: xml_names.h:79
#define PCMK_XE_STATUS
Definition: xml_names.h:204
int cib__signon_query(pcmk__output_t *out, cib_t **cib, xmlNode **cib_object)
Definition: cib_utils.c:841
int pcmk__verify(pcmk_scheduler_t *scheduler, pcmk__output_t *out, xmlNode **cib_object)
Definition: pcmk_verify.c:49
int pcmk_verify(xmlNodePtr *xml, const char *cib_source)
Verify that a CIB is error-free or output errors and warnings.
Definition: pcmk_verify.c:125
#define pcmk__config_err(fmt...)
crm_exit_t pcmk_rc2exitc(int rc)
Map a function return code to the most similar exit code.
Definition: results.c:810
int pcmk__update_configured_schema(xmlNode **xml, bool to_logs)
Update XML from its configured schema to the latest major series.
Definition: schemas.c:1159
pcmk__scheduler_private_t * priv
Definition: scheduler.h:99
High Level API.
void pcmk__schedule_actions(xmlNode *cib, unsigned long long flags, pcmk_scheduler_t *scheduler)
void pcmk__xml_output_finish(pcmk__output_t *out, crm_exit_t exit_status, xmlNodePtr *xml)
Definition: output.c:271
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:609
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml_element.c:407
Scheduler API.
void pcmk__xml_free(xmlNode *xml)
Definition: xml.c:789
xmlNode * pcmk_find_cib_element(xmlNode *cib, const char *element_name)
Find an element in the CIB.
Definition: cib.c:172
bool pcmk__config_has_error
Definition: utils.c:42
int pcmk__xml_output_new(pcmk__output_t **out, xmlNodePtr *xml)
Definition: output.c:244
bool pcmk__validate_xml(xmlNode *xml_blob, const char *validation, xmlRelaxNGValidityErrorFunc error_handler, void *error_handler_context)
Definition: schemas.c:728
int(*) int(*) void(* err)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
void pcmk__register_lib_messages(pcmk__output_t *out)
Definition: pcmk_output.c:2709
void pe__register_messages(pcmk__output_t *out)
Definition: pe_output.c:3470
pcmk_scheduler_t * pe_new_working_set(void)
Create a new object to hold scheduler data.
Definition: status.c:34
Function and executable result codes.
xmlNode * pcmk__xml_parse(const char *input)
Definition: xml_io.c:168
xmlNode * pcmk__xml_read(const char *filename)
Definition: xml_io.c:102
#define pcmk__assert(expr)
bool pcmk__config_has_warning
Definition: utils.c:43
void pe_free_working_set(pcmk_scheduler_t *scheduler)
Free scheduler data.
Definition: status.c:56
pcmk_scheduler_t * scheduler
This structure contains everything that makes up a single output formatter.
const char * pcmk__highest_schema_name(void)
Definition: schemas.c:97
int pcmk__parse_cib(pcmk__output_t *out, const char *cib_source, xmlNodePtr *cib_object)
Definition: pcmk_verify.c:26
uint64_t flags
Definition: remote.c:211