pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
patchset_display.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-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
12#include <crm/common/xml.h>
13
14#include "crmcommon_private.h"
15
40static int
41xml_show_patchset_header(pcmk__output_t *out, const xmlNode *patchset)
42{
43 int rc = pcmk_rc_no_output;
44 int add[] = { 0, 0, 0 };
45 int del[] = { 0, 0, 0 };
46
47 xml_patch_versions(patchset, add, del);
48
49 if ((add[0] != del[0]) || (add[1] != del[1]) || (add[2] != del[2])) {
50 const char *fmt = crm_element_value(patchset, PCMK_XA_FORMAT);
51 const char *digest = crm_element_value(patchset, PCMK__XA_DIGEST);
52
53 out->info(out, "Diff: --- %d.%d.%d %s", del[0], del[1], del[2], fmt);
54 rc = out->info(out, "Diff: +++ %d.%d.%d %s",
55 add[0], add[1], add[2], digest);
56
57 } else if ((add[0] != 0) || (add[1] != 0) || (add[2] != 0)) {
58 rc = out->info(out, "Local-only Change: %d.%d.%d",
59 add[0], add[1], add[2]);
60 }
61
62 return rc;
63}
64
79static int
80xml_show_patchset(pcmk__output_t *out, const xmlNode *patchset)
81{
82 int rc = xml_show_patchset_header(out, patchset);
83 int temp_rc = pcmk_rc_no_output;
84
85 for (const xmlNode *change = pcmk__xe_first_child(patchset, NULL, NULL,
86 NULL);
87 change != NULL; change = pcmk__xe_next(change, NULL)) {
88
89 const char *op = crm_element_value(change, PCMK_XA_OPERATION);
90 const char *xpath = crm_element_value(change, PCMK_XA_PATH);
91
92 if (op == NULL) {
93 continue;
94 }
95
96 if (strcmp(op, PCMK_VALUE_CREATE) == 0) {
97 char *prefix = crm_strdup_printf(PCMK__XML_PREFIX_CREATED " %s: ",
98 xpath);
99
100 temp_rc = pcmk__xml_show(out, prefix, change->children, 0,
102 rc = pcmk__output_select_rc(rc, temp_rc);
103
104 // Overwrite all except the first two characters with spaces
105 for (char *ch = prefix + 2; *ch != '\0'; ch++) {
106 *ch = ' ';
107 }
108
109 temp_rc = pcmk__xml_show(out, prefix, change->children, 0,
113 rc = pcmk__output_select_rc(rc, temp_rc);
114 free(prefix);
115
116 } else if (strcmp(op, PCMK_VALUE_MOVE) == 0) {
117 const char *position = crm_element_value(change, PCMK_XE_POSITION);
118
119 temp_rc = out->info(out,
120 PCMK__XML_PREFIX_MOVED " %s moved to offset %s",
121 xpath, position);
122 rc = pcmk__output_select_rc(rc, temp_rc);
123
124 } else if (strcmp(op, PCMK_VALUE_MODIFY) == 0) {
125 xmlNode *clist = pcmk__xe_first_child(change, PCMK_XE_CHANGE_LIST,
126 NULL, NULL);
127 GString *buffer_set = NULL;
128 GString *buffer_unset = NULL;
129
130 for (const xmlNode *child = pcmk__xe_first_child(clist, NULL, NULL,
131 NULL);
132 child != NULL; child = pcmk__xe_next(child, NULL)) {
133
134 const char *name = crm_element_value(child, PCMK_XA_NAME);
135
137 if (op == NULL) {
138 continue;
139 }
140
141 if (strcmp(op, "set") == 0) {
142 const char *value = crm_element_value(child, PCMK_XA_VALUE);
143
144 pcmk__add_separated_word(&buffer_set, 256, "@", ", ");
145 pcmk__g_strcat(buffer_set, name, "=", value, NULL);
146
147 } else if (strcmp(op, "unset") == 0) {
148 pcmk__add_separated_word(&buffer_unset, 256, "@", ", ");
149 g_string_append(buffer_unset, name);
150 }
151 }
152
153 if (buffer_set != NULL) {
154 temp_rc = out->info(out, "+ %s: %s", xpath, buffer_set->str);
155 rc = pcmk__output_select_rc(rc, temp_rc);
156 g_string_free(buffer_set, TRUE);
157 }
158
159 if (buffer_unset != NULL) {
160 temp_rc = out->info(out, "-- %s: %s",
161 xpath, buffer_unset->str);
162 rc = pcmk__output_select_rc(rc, temp_rc);
163 g_string_free(buffer_unset, TRUE);
164 }
165
166 } else if (strcmp(op, PCMK_VALUE_DELETE) == 0) {
167 int position = -1;
168
169 crm_element_value_int(change, PCMK_XE_POSITION, &position);
170 if (position >= 0) {
171 temp_rc = out->info(out, "-- %s (%d)", xpath, position);
172 } else {
173 temp_rc = out->info(out, "-- %s", xpath);
174 }
175 rc = pcmk__output_select_rc(rc, temp_rc);
176 }
177 }
178
179 return rc;
180}
181
197PCMK__OUTPUT_ARGS("xml-patchset", "const xmlNode *")
198static int
199xml_patchset_default(pcmk__output_t *out, va_list args)
200{
201 const xmlNode *patchset = va_arg(args, const xmlNode *);
202
203 int format = 1;
204
205 if (patchset == NULL) {
206 crm_trace("Empty patch");
207 return pcmk_rc_no_output;
208 }
209
210 crm_element_value_int(patchset, PCMK_XA_FORMAT, &format);
211 if (format != 2) {
212 crm_err("Unknown patch format: %d", format);
214 }
215
216 return xml_show_patchset(out, patchset);
217}
218
234PCMK__OUTPUT_ARGS("xml-patchset", "const xmlNode *")
235static int
236xml_patchset_log(pcmk__output_t *out, va_list args)
237{
238 static struct qb_log_callsite *patchset_cs = NULL;
239
240 const xmlNode *patchset = va_arg(args, const xmlNode *);
241
242 uint8_t log_level = pcmk__output_get_log_level(out);
243 int format = 1;
244
245 if (log_level == LOG_NEVER) {
246 return pcmk_rc_no_output;
247 }
248
249 if (patchset == NULL) {
250 crm_trace("Empty patch");
251 return pcmk_rc_no_output;
252 }
253
254 if (patchset_cs == NULL) {
255 patchset_cs = qb_log_callsite_get(__func__, __FILE__, "xml-patchset",
256 log_level, __LINE__,
258 }
259
260 if (!crm_is_callsite_active(patchset_cs, log_level, crm_trace_nonlog)) {
261 // Nothing would be logged, so skip all the work
262 return pcmk_rc_no_output;
263 }
264
265 crm_element_value_int(patchset, PCMK_XA_FORMAT, &format);
266 if (format != 2) {
267 crm_err("Unknown patch format: %d", format);
269 }
270
271 return xml_show_patchset(out, patchset);
272}
273
289PCMK__OUTPUT_ARGS("xml-patchset", "const xmlNode *")
290static int
291xml_patchset_xml(pcmk__output_t *out, va_list args)
292{
293 const xmlNode *patchset = va_arg(args, const xmlNode *);
294
295 if (patchset != NULL) {
296 GString *buf = g_string_sized_new(1024);
297
299 0);
300
301 out->output_xml(out, PCMK_XE_XML_PATCHSET, buf->str);
302 g_string_free(buf, TRUE);
303 return pcmk_rc_ok;
304 }
305 crm_trace("Empty patch");
306 return pcmk_rc_no_output;
307}
308
309static pcmk__message_entry_t fmt_functions[] = {
310 { "xml-patchset", "default", xml_patchset_default },
311 { "xml-patchset", "log", xml_patchset_log },
312 { "xml-patchset", "xml", xml_patchset_xml },
313
314 { NULL, NULL, NULL }
315};
316
323void
const char * name
Definition cib.c:26
#define PCMK__XML_PREFIX_MOVED
XML has been moved.
#define PCMK__XML_PREFIX_CREATED
XML is newly created.
gboolean crm_is_callsite_active(struct qb_log_callsite *cs, uint8_t level, uint32_t tags)
Definition logging.c:694
unsigned int crm_trace_nonlog
Definition logging.c:46
#define crm_err(fmt, args...)
Definition logging.h:357
#define LOG_NEVER
Definition logging.h:48
#define crm_trace(fmt, args...)
Definition logging.h:370
#define PCMK_VALUE_MOVE
Definition options.h:177
#define PCMK_VALUE_DELETE
Definition options.h:146
#define PCMK_VALUE_MODIFY
Definition options.h:176
#define PCMK_VALUE_CREATE
Definition options.h:141
void pcmk__register_messages(pcmk__output_t *out, const pcmk__message_entry_t *table)
Definition output.c:206
uint8_t pcmk__output_get_log_level(const pcmk__output_t *out)
Definition output_log.c:363
void pcmk__register_patchset_messages(pcmk__output_t *out)
@ pcmk_rc_no_output
Definition results.h:128
@ pcmk_rc_ok
Definition results.h:159
@ pcmk_rc_bad_xml_patch
Definition results.h:118
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition strings.c:1299
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
Definition strings.c:796
This structure contains everything that makes up a single output formatter.
int(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
Wrappers for and extensions to libxml2.
bool xml_patch_versions(const xmlNode *patchset, int add[3], int del[3])
Definition patchset.c:315
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
Definition xml_element.c:43
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
@ pcmk__xml_fmt_close
Include the closing tag of an XML element.
@ pcmk__xml_fmt_children
Include the children of an XML element.
@ pcmk__xml_fmt_open
Include the opening tag of an XML element, and include XML comments.
@ pcmk__xml_fmt_pretty
Include indentation and newlines.
@ pcmk__xml_fmt_text
Include XML text nodes.
int pcmk__xml_show(pcmk__output_t *out, const char *prefix, const xmlNode *data, int depth, uint32_t options)
void pcmk__xml_string(const xmlNode *data, uint32_t options, GString *buffer, int depth)
Definition xml_io.c:370
#define PCMK_XA_FORMAT
Definition xml_names.h:291
#define PCMK_XA_OPERATION
Definition xml_names.h:349
#define PCMK_XA_PATH
Definition xml_names.h:355
#define PCMK_XE_CHANGE_LIST
Definition xml_names.h:76
#define PCMK_XA_VALUE
Definition xml_names.h:442
#define PCMK_XE_XML_PATCHSET
Definition xml_names.h:222
#define PCMK_XA_NAME
Definition xml_names.h:330
#define PCMK_XE_POSITION
Definition xml_names.h:163
#define PCMK__XA_DIGEST