Line data Source code
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 <sys/param.h>
13 :
14 : #include <crm/crm.h>
15 :
16 : #include <stdio.h>
17 : #include <sys/types.h>
18 : #include <unistd.h>
19 :
20 : #include <stdlib.h>
21 : #include <errno.h>
22 : #include <fcntl.h>
23 : #include <libgen.h>
24 :
25 : #include <crm/common/xml.h>
26 : #include <crm/common/xml_internal.h>
27 : #include <crm/common/output_internal.h>
28 : #include <crm/cib/internal.h>
29 :
30 : static pcmk__output_t *
31 0 : new_output_object(const char *ty)
32 : {
33 0 : int rc = pcmk_rc_ok;
34 0 : pcmk__output_t *out = NULL;
35 0 : const char* argv[] = { "", NULL };
36 0 : pcmk__supported_format_t formats[] = {
37 : PCMK__SUPPORTED_FORMAT_LOG,
38 : PCMK__SUPPORTED_FORMAT_TEXT,
39 : { NULL, NULL, NULL }
40 : };
41 :
42 0 : pcmk__register_formats(NULL, formats);
43 0 : rc = pcmk__output_new(&out, ty, NULL, (char**)argv);
44 0 : if ((rc != pcmk_rc_ok) || (out == NULL)) {
45 0 : crm_err("Can't out due to internal error: %s", pcmk_rc_str(rc));
46 0 : return NULL;
47 : }
48 :
49 0 : return out;
50 : }
51 :
52 : static int
53 0 : find_attr(cib_t *cib, const char *section, const char *node_uuid,
54 : const char *attr_set_type, const char *set_name, const char *attr_id,
55 : const char *attr_name, const char *user_name, xmlNode **result)
56 : {
57 0 : int rc = pcmk_rc_ok;
58 :
59 0 : const char *xpath_base = NULL;
60 0 : GString *xpath = NULL;
61 0 : xmlNode *xml_search = NULL;
62 0 : const char *set_type = NULL;
63 0 : const char *node_type = NULL;
64 :
65 0 : if (attr_set_type) {
66 0 : set_type = attr_set_type;
67 : } else {
68 0 : set_type = PCMK_XE_INSTANCE_ATTRIBUTES;
69 : }
70 :
71 0 : if (pcmk__str_eq(section, PCMK_XE_CRM_CONFIG, pcmk__str_casei)) {
72 0 : node_uuid = NULL;
73 0 : set_type = PCMK_XE_CLUSTER_PROPERTY_SET;
74 :
75 0 : } else if (pcmk__strcase_any_of(section,
76 : PCMK_XE_OP_DEFAULTS, PCMK_XE_RSC_DEFAULTS,
77 : NULL)) {
78 0 : node_uuid = NULL;
79 0 : set_type = PCMK_XE_META_ATTRIBUTES;
80 :
81 0 : } else if (pcmk__str_eq(section, PCMK_XE_TICKETS, pcmk__str_casei)) {
82 0 : node_uuid = NULL;
83 0 : section = PCMK_XE_STATUS;
84 0 : node_type = PCMK_XE_TICKETS;
85 :
86 0 : } else if (node_uuid == NULL) {
87 0 : return EINVAL;
88 : }
89 :
90 0 : xpath_base = pcmk_cib_xpath_for(section);
91 0 : if (xpath_base == NULL) {
92 0 : crm_warn("%s CIB section not known", section);
93 0 : return ENOMSG;
94 : }
95 :
96 0 : xpath = g_string_sized_new(1024);
97 : g_string_append(xpath, xpath_base);
98 :
99 0 : if (pcmk__str_eq(node_type, PCMK_XE_TICKETS, pcmk__str_casei)) {
100 0 : pcmk__g_strcat(xpath, "//", node_type, NULL);
101 :
102 0 : } else if (node_uuid) {
103 0 : const char *node_type = PCMK_XE_NODE;
104 :
105 0 : if (pcmk__str_eq(section, PCMK_XE_STATUS, pcmk__str_casei)) {
106 0 : node_type = PCMK__XE_NODE_STATE;
107 0 : set_type = PCMK__XE_TRANSIENT_ATTRIBUTES;
108 : }
109 0 : pcmk__g_strcat(xpath,
110 : "//", node_type, "[@" PCMK_XA_ID "='", node_uuid, "']",
111 : NULL);
112 : }
113 :
114 0 : pcmk__g_strcat(xpath, "//", set_type, NULL);
115 0 : if (set_name) {
116 0 : pcmk__g_strcat(xpath, "[@" PCMK_XA_ID "='", set_name, "']", NULL);
117 : }
118 :
119 0 : g_string_append(xpath, "//nvpair");
120 :
121 0 : if (attr_id && attr_name) {
122 0 : pcmk__g_strcat(xpath,
123 : "[@" PCMK_XA_ID "='", attr_id, "' "
124 : "and @" PCMK_XA_NAME "='", attr_name, "']", NULL);
125 :
126 0 : } else if (attr_id) {
127 0 : pcmk__g_strcat(xpath, "[@" PCMK_XA_ID "='", attr_id, "']", NULL);
128 :
129 0 : } else if (attr_name) {
130 0 : pcmk__g_strcat(xpath, "[@" PCMK_XA_NAME "='", attr_name, "']", NULL);
131 : }
132 :
133 0 : rc = cib_internal_op(cib, PCMK__CIB_REQUEST_QUERY, NULL,
134 0 : (const char *) xpath->str, NULL, &xml_search,
135 : cib_sync_call|cib_scope_local|cib_xpath, user_name);
136 0 : rc = pcmk_legacy2rc(rc);
137 :
138 0 : if (rc != pcmk_rc_ok) {
139 0 : crm_trace("Query failed for attribute %s (section=%s, node=%s, set=%s, xpath=%s): %s",
140 : attr_name, section, pcmk__s(node_uuid, "<null>"),
141 : pcmk__s(set_name, "<null>"), (const char *) xpath->str,
142 : pcmk_rc_str(rc));
143 : } else {
144 0 : crm_log_xml_debug(xml_search, "Match");
145 : }
146 :
147 0 : g_string_free(xpath, TRUE);
148 0 : *result = xml_search;
149 0 : return rc;
150 : }
151 :
152 : static int
153 0 : handle_multiples(pcmk__output_t *out, xmlNode *search, const char *attr_name)
154 : {
155 0 : if ((search != NULL) && (search->children != NULL)) {
156 0 : pcmk__warn_multiple_name_matches(out, search, attr_name);
157 0 : return ENOTUNIQ;
158 : } else {
159 0 : return pcmk_rc_ok;
160 : }
161 : }
162 :
163 : int
164 0 : cib__update_node_attr(pcmk__output_t *out, cib_t *cib, int call_options, const char *section,
165 : const char *node_uuid, const char *set_type, const char *set_name,
166 : const char *attr_id, const char *attr_name, const char *attr_value,
167 : const char *user_name, const char *node_type)
168 : {
169 0 : const char *tag = NULL;
170 0 : int rc = pcmk_rc_ok;
171 0 : xmlNode *xml_top = NULL;
172 0 : xmlNode *xml_obj = NULL;
173 0 : xmlNode *xml_search = NULL;
174 :
175 0 : char *local_attr_id = NULL;
176 0 : char *local_set_name = NULL;
177 :
178 0 : CRM_CHECK((out != NULL) && (cib != NULL) && (section != NULL)
179 : && ((attr_id != NULL) || (attr_name != NULL))
180 : && (attr_value != NULL), return EINVAL);
181 :
182 0 : rc = find_attr(cib, section, node_uuid, set_type, set_name, attr_id,
183 : attr_name, user_name, &xml_search);
184 :
185 0 : if (rc == pcmk_rc_ok) {
186 0 : if (handle_multiples(out, xml_search, attr_name) == ENOTUNIQ) {
187 0 : free_xml(xml_search);
188 0 : return ENOTUNIQ;
189 : } else {
190 0 : local_attr_id = crm_element_value_copy(xml_search, PCMK_XA_ID);
191 0 : attr_id = local_attr_id;
192 0 : free_xml(xml_search);
193 0 : goto do_modify;
194 : }
195 :
196 0 : } else if (rc != ENXIO) {
197 0 : free_xml(xml_search);
198 0 : return rc;
199 :
200 : /* } else if(attr_id == NULL) { */
201 : /* return EINVAL; */
202 :
203 : } else {
204 0 : free_xml(xml_search);
205 0 : crm_trace("%s does not exist, create it", attr_name);
206 0 : if (pcmk__str_eq(section, PCMK_XE_TICKETS, pcmk__str_casei)) {
207 0 : node_uuid = NULL;
208 0 : section = PCMK_XE_STATUS;
209 0 : node_type = PCMK_XE_TICKETS;
210 :
211 0 : xml_top = pcmk__xe_create(xml_obj, PCMK_XE_STATUS);
212 0 : xml_obj = pcmk__xe_create(xml_top, PCMK_XE_TICKETS);
213 :
214 0 : } else if (pcmk__str_eq(section, PCMK_XE_NODES, pcmk__str_casei)) {
215 :
216 0 : if (node_uuid == NULL) {
217 0 : return EINVAL;
218 : }
219 :
220 0 : if (pcmk__str_eq(node_type, PCMK_VALUE_REMOTE, pcmk__str_casei)) {
221 0 : xml_top = pcmk__xe_create(xml_obj, PCMK_XE_NODES);
222 0 : xml_obj = pcmk__xe_create(xml_top, PCMK_XE_NODE);
223 0 : crm_xml_add(xml_obj, PCMK_XA_TYPE, PCMK_VALUE_REMOTE);
224 0 : crm_xml_add(xml_obj, PCMK_XA_ID, node_uuid);
225 0 : crm_xml_add(xml_obj, PCMK_XA_UNAME, node_uuid);
226 : } else {
227 0 : tag = PCMK_XE_NODE;
228 : }
229 :
230 0 : } else if (pcmk__str_eq(section, PCMK_XE_STATUS, pcmk__str_casei)) {
231 0 : tag = PCMK__XE_TRANSIENT_ATTRIBUTES;
232 0 : if (node_uuid == NULL) {
233 0 : return EINVAL;
234 : }
235 :
236 0 : xml_top = pcmk__xe_create(xml_obj, PCMK__XE_NODE_STATE);
237 0 : crm_xml_add(xml_top, PCMK_XA_ID, node_uuid);
238 0 : xml_obj = xml_top;
239 :
240 : } else {
241 0 : tag = section;
242 0 : node_uuid = NULL;
243 : }
244 :
245 0 : if (set_name == NULL) {
246 0 : if (pcmk__str_eq(section, PCMK_XE_CRM_CONFIG, pcmk__str_casei)) {
247 : local_set_name =
248 0 : pcmk__str_copy(PCMK_VALUE_CIB_BOOTSTRAP_OPTIONS);
249 :
250 0 : } else if (pcmk__str_eq(node_type, PCMK_XE_TICKETS,
251 : pcmk__str_casei)) {
252 0 : local_set_name = crm_strdup_printf("%s-%s", section,
253 : PCMK_XE_TICKETS);
254 :
255 0 : } else if (node_uuid) {
256 0 : local_set_name = crm_strdup_printf("%s-%s", section, node_uuid);
257 :
258 0 : if (set_type) {
259 0 : char *tmp_set_name = local_set_name;
260 :
261 0 : local_set_name = crm_strdup_printf("%s-%s", tmp_set_name,
262 : set_type);
263 0 : free(tmp_set_name);
264 : }
265 : } else {
266 0 : local_set_name = crm_strdup_printf("%s-options", section);
267 : }
268 0 : set_name = local_set_name;
269 : }
270 :
271 0 : if (attr_id == NULL) {
272 0 : local_attr_id = crm_strdup_printf("%s-%s", set_name, attr_name);
273 0 : crm_xml_sanitize_id(local_attr_id);
274 0 : attr_id = local_attr_id;
275 :
276 0 : } else if (attr_name == NULL) {
277 0 : attr_name = attr_id;
278 : }
279 :
280 0 : crm_trace("Creating %s/%s", section, tag);
281 0 : if (tag != NULL) {
282 0 : xml_obj = pcmk__xe_create(xml_obj, tag);
283 0 : crm_xml_add(xml_obj, PCMK_XA_ID, node_uuid);
284 0 : if (xml_top == NULL) {
285 0 : xml_top = xml_obj;
286 : }
287 : }
288 :
289 0 : if ((node_uuid == NULL)
290 0 : && !pcmk__str_eq(node_type, PCMK_XE_TICKETS, pcmk__str_casei)) {
291 :
292 0 : if (pcmk__str_eq(section, PCMK_XE_CRM_CONFIG, pcmk__str_casei)) {
293 0 : xml_obj = pcmk__xe_create(xml_obj,
294 : PCMK_XE_CLUSTER_PROPERTY_SET);
295 : } else {
296 0 : xml_obj = pcmk__xe_create(xml_obj, PCMK_XE_META_ATTRIBUTES);
297 : }
298 :
299 0 : } else if (set_type) {
300 0 : xml_obj = pcmk__xe_create(xml_obj, set_type);
301 :
302 : } else {
303 0 : xml_obj = pcmk__xe_create(xml_obj, PCMK_XE_INSTANCE_ATTRIBUTES);
304 : }
305 0 : crm_xml_add(xml_obj, PCMK_XA_ID, set_name);
306 :
307 0 : if (xml_top == NULL) {
308 0 : xml_top = xml_obj;
309 : }
310 : }
311 :
312 0 : do_modify:
313 0 : xml_obj = crm_create_nvpair_xml(xml_obj, attr_id, attr_name, attr_value);
314 0 : if (xml_top == NULL) {
315 0 : xml_top = xml_obj;
316 : }
317 :
318 0 : crm_log_xml_trace(xml_top, "update_attr");
319 0 : rc = cib_internal_op(cib, PCMK__CIB_REQUEST_MODIFY, NULL, section, xml_top,
320 : NULL, call_options, user_name);
321 :
322 0 : if (!pcmk_is_set(call_options, cib_sync_call) && (cib->variant != cib_file)
323 0 : && (rc >= 0)) {
324 : // For async call, positive rc is the call ID (file always synchronous)
325 0 : rc = pcmk_rc_ok;
326 : } else {
327 0 : rc = pcmk_legacy2rc(rc);
328 : }
329 :
330 0 : if (rc != pcmk_rc_ok) {
331 0 : out->err(out, "Error setting %s=%s (section=%s, set=%s): %s",
332 : attr_name, attr_value, section, pcmk__s(set_name, "<null>"),
333 : pcmk_rc_str(rc));
334 0 : crm_log_xml_info(xml_top, "Update");
335 : }
336 :
337 0 : free(local_set_name);
338 0 : free(local_attr_id);
339 0 : free_xml(xml_top);
340 :
341 0 : return rc;
342 : }
343 :
344 : int
345 0 : cib__get_node_attrs(pcmk__output_t *out, cib_t *cib, const char *section,
346 : const char *node_uuid, const char *set_type, const char *set_name,
347 : const char *attr_id, const char *attr_name, const char *user_name,
348 : xmlNode **result)
349 : {
350 0 : int rc = pcmk_rc_ok;
351 :
352 0 : CRM_ASSERT(result != NULL);
353 0 : CRM_CHECK(section != NULL, return EINVAL);
354 :
355 0 : *result = NULL;
356 :
357 0 : rc = find_attr(cib, section, node_uuid, set_type, set_name, attr_id, attr_name,
358 : user_name, result);
359 :
360 0 : if (rc != pcmk_rc_ok) {
361 0 : crm_trace("Query failed for attribute %s (section=%s node=%s set=%s): %s",
362 : pcmk__s(attr_name, "with unspecified name"),
363 : section, pcmk__s(set_name, "<null>"),
364 : pcmk__s(node_uuid, "<null>"), pcmk_rc_str(rc));
365 : }
366 :
367 0 : return rc;
368 : }
369 :
370 : int
371 0 : cib__delete_node_attr(pcmk__output_t *out, cib_t *cib, int options, const char *section,
372 : const char *node_uuid, const char *set_type, const char *set_name,
373 : const char *attr_id, const char *attr_name, const char *attr_value,
374 : const char *user_name)
375 : {
376 0 : int rc = pcmk_rc_ok;
377 0 : xmlNode *xml_obj = NULL;
378 0 : xmlNode *xml_search = NULL;
379 0 : char *local_attr_id = NULL;
380 :
381 0 : CRM_CHECK(section != NULL, return EINVAL);
382 0 : CRM_CHECK(attr_name != NULL || attr_id != NULL, return EINVAL);
383 :
384 0 : if (attr_id == NULL) {
385 0 : rc = find_attr(cib, section, node_uuid, set_type, set_name, attr_id,
386 : attr_name, user_name, &xml_search);
387 :
388 0 : if (rc != pcmk_rc_ok || handle_multiples(out, xml_search, attr_name) == ENOTUNIQ) {
389 0 : free_xml(xml_search);
390 0 : return rc;
391 : } else {
392 0 : local_attr_id = crm_element_value_copy(xml_search, PCMK_XA_ID);
393 0 : attr_id = local_attr_id;
394 0 : free_xml(xml_search);
395 : }
396 : }
397 :
398 0 : xml_obj = crm_create_nvpair_xml(NULL, attr_id, attr_name, attr_value);
399 :
400 0 : rc = cib_internal_op(cib, PCMK__CIB_REQUEST_DELETE, NULL, section, xml_obj,
401 : NULL, options, user_name);
402 :
403 0 : if (!pcmk_is_set(options, cib_sync_call) && (cib->variant != cib_file)
404 0 : && (rc >= 0)) {
405 : // For async call, positive rc is the call ID (file always synchronous)
406 0 : rc = pcmk_rc_ok;
407 : } else {
408 0 : rc = pcmk_legacy2rc(rc);
409 : }
410 :
411 0 : if (rc == pcmk_rc_ok) {
412 0 : out->info(out, "Deleted %s %s: id=%s%s%s%s%s",
413 : section, node_uuid ? "attribute" : "option", local_attr_id,
414 : set_name ? " set=" : "", set_name ? set_name : "",
415 : attr_name ? " name=" : "", attr_name ? attr_name : "");
416 : }
417 0 : free(local_attr_id);
418 0 : free_xml(xml_obj);
419 0 : return rc;
420 : }
421 :
422 : int
423 0 : find_nvpair_attr_delegate(cib_t *cib, const char *attr, const char *section,
424 : const char *node_uuid, const char *attr_set_type, const char *set_name,
425 : const char *attr_id, const char *attr_name, gboolean to_console,
426 : char **value, const char *user_name)
427 : {
428 0 : pcmk__output_t *out = NULL;
429 0 : xmlNode *xml_search = NULL;
430 0 : int rc = pcmk_ok;
431 :
432 0 : out = new_output_object(to_console ? "text" : "log");
433 0 : if (out == NULL) {
434 0 : return pcmk_err_generic;
435 : }
436 :
437 0 : rc = find_attr(cib, section, node_uuid, attr_set_type, set_name, attr_id,
438 : attr_name, user_name, &xml_search);
439 :
440 0 : if (rc == pcmk_rc_ok) {
441 0 : rc = handle_multiples(out, xml_search, attr_name);
442 :
443 0 : if (rc == pcmk_rc_ok) {
444 0 : pcmk__str_update(value, crm_element_value(xml_search, attr));
445 : }
446 : }
447 :
448 0 : out->finish(out, CRM_EX_OK, true, NULL);
449 0 : free_xml(xml_search);
450 0 : pcmk__output_free(out);
451 0 : return pcmk_rc2legacy(rc);
452 : }
453 :
454 : int
455 0 : update_attr_delegate(cib_t *cib, int call_options, const char *section,
456 : const char *node_uuid, const char *set_type, const char *set_name,
457 : const char *attr_id, const char *attr_name, const char *attr_value,
458 : gboolean to_console, const char *user_name, const char *node_type)
459 : {
460 0 : pcmk__output_t *out = NULL;
461 0 : int rc = pcmk_ok;
462 :
463 0 : out = new_output_object(to_console ? "text" : "log");
464 0 : if (out == NULL) {
465 0 : return pcmk_err_generic;
466 : }
467 :
468 0 : rc = cib__update_node_attr(out, cib, call_options, section, node_uuid, set_type,
469 : set_name, attr_id, attr_name, attr_value, user_name,
470 : node_type);
471 :
472 0 : out->finish(out, CRM_EX_OK, true, NULL);
473 0 : pcmk__output_free(out);
474 0 : return pcmk_rc2legacy(rc);
475 : }
476 :
477 : int
478 0 : read_attr_delegate(cib_t *cib, const char *section, const char *node_uuid,
479 : const char *set_type, const char *set_name, const char *attr_id,
480 : const char *attr_name, char **attr_value, gboolean to_console,
481 : const char *user_name)
482 : {
483 0 : pcmk__output_t *out = NULL;
484 0 : xmlNode *result = NULL;
485 0 : int rc = pcmk_ok;
486 :
487 0 : out = new_output_object(to_console ? "text" : "log");
488 0 : if (out == NULL) {
489 0 : return pcmk_err_generic;
490 : }
491 :
492 0 : rc = cib__get_node_attrs(out, cib, section, node_uuid, set_type, set_name,
493 : attr_id, attr_name, user_name, &result);
494 :
495 0 : if (rc == pcmk_rc_ok) {
496 0 : if (result->children == NULL) {
497 0 : pcmk__str_update(attr_value,
498 : crm_element_value(result, PCMK_XA_VALUE));
499 : } else {
500 0 : rc = ENOTUNIQ;
501 : }
502 : }
503 :
504 0 : out->finish(out, CRM_EX_OK, true, NULL);
505 0 : free_xml(result);
506 0 : pcmk__output_free(out);
507 0 : return pcmk_rc2legacy(rc);
508 : }
509 :
510 : int
511 0 : delete_attr_delegate(cib_t *cib, int options, const char *section, const char *node_uuid,
512 : const char *set_type, const char *set_name, const char *attr_id,
513 : const char *attr_name, const char *attr_value, gboolean to_console,
514 : const char *user_name)
515 : {
516 0 : pcmk__output_t *out = NULL;
517 0 : int rc = pcmk_ok;
518 :
519 0 : out = new_output_object(to_console ? "text" : "log");
520 0 : if (out == NULL) {
521 0 : return pcmk_err_generic;
522 : }
523 :
524 0 : rc = cib__delete_node_attr(out, cib, options, section, node_uuid, set_type,
525 : set_name, attr_id, attr_name, attr_value, user_name);
526 :
527 0 : out->finish(out, CRM_EX_OK, true, NULL);
528 0 : pcmk__output_free(out);
529 0 : return pcmk_rc2legacy(rc);
530 : }
531 :
532 : /*!
533 : * \internal
534 : * \brief Parse node UUID from search result
535 : *
536 : * \param[in] result XML search result
537 : * \param[out] uuid If non-NULL, where to store parsed UUID
538 : * \param[out] is_remote If non-NULL, set TRUE if result is remote node
539 : *
540 : * \return pcmk_ok if UUID was successfully parsed, -ENXIO otherwise
541 : */
542 : static int
543 0 : get_uuid_from_result(const xmlNode *result, char **uuid, int *is_remote)
544 : {
545 0 : int rc = -ENXIO;
546 0 : const char *parsed_uuid = NULL;
547 0 : int parsed_is_remote = FALSE;
548 :
549 0 : if (result == NULL) {
550 0 : return rc;
551 : }
552 :
553 : /* If there are multiple results, the first is sufficient */
554 0 : if (pcmk__xe_is(result, PCMK__XE_XPATH_QUERY)) {
555 0 : result = pcmk__xe_first_child(result, NULL, NULL, NULL);
556 0 : CRM_CHECK(result != NULL, return rc);
557 : }
558 :
559 0 : if (pcmk__xe_is(result, PCMK_XE_NODE)) {
560 : // Result is PCMK_XE_NODE element from PCMK_XE_NODES section
561 :
562 0 : if (pcmk__str_eq(crm_element_value(result, PCMK_XA_TYPE),
563 : PCMK_VALUE_REMOTE, pcmk__str_casei)) {
564 0 : parsed_uuid = crm_element_value(result, PCMK_XA_UNAME);
565 0 : parsed_is_remote = TRUE;
566 : } else {
567 0 : parsed_uuid = pcmk__xe_id(result);
568 0 : parsed_is_remote = FALSE;
569 : }
570 :
571 0 : } else if (pcmk__xe_is(result, PCMK_XE_PRIMITIVE)) {
572 : /* Result is <primitive> for ocf:pacemaker:remote resource */
573 :
574 0 : parsed_uuid = pcmk__xe_id(result);
575 0 : parsed_is_remote = TRUE;
576 :
577 0 : } else if (pcmk__xe_is(result, PCMK_XE_NVPAIR)) {
578 : /* Result is PCMK_META_REMOTE_NODE parameter of <primitive> for guest
579 : * node
580 : */
581 :
582 0 : parsed_uuid = crm_element_value(result, PCMK_XA_VALUE);
583 0 : parsed_is_remote = TRUE;
584 :
585 0 : } else if (pcmk__xe_is(result, PCMK__XE_NODE_STATE)) {
586 : // Result is PCMK__XE_NODE_STATE element from PCMK_XE_STATUS section
587 :
588 0 : parsed_uuid = crm_element_value(result, PCMK_XA_UNAME);
589 0 : if (pcmk__xe_attr_is_true(result, PCMK_XA_REMOTE_NODE)) {
590 0 : parsed_is_remote = TRUE;
591 : }
592 : }
593 :
594 0 : if (parsed_uuid) {
595 0 : if (uuid) {
596 0 : *uuid = strdup(parsed_uuid);
597 : }
598 0 : if (is_remote) {
599 0 : *is_remote = parsed_is_remote;
600 : }
601 0 : rc = pcmk_ok;
602 : }
603 :
604 0 : return rc;
605 : }
606 :
607 : /* Search string to find a node by name, as:
608 : * - cluster or remote node in nodes section
609 : * - remote node in resources section
610 : * - guest node in resources section
611 : * - orphaned remote node or bundle guest node in status section
612 : */
613 : #define XPATH_UPPER_TRANS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
614 : #define XPATH_LOWER_TRANS "abcdefghijklmnopqrstuvwxyz"
615 : #define XPATH_NODE \
616 : "/" PCMK_XE_CIB "/" PCMK_XE_CONFIGURATION "/" PCMK_XE_NODES \
617 : "/" PCMK_XE_NODE "[translate(@" PCMK_XA_UNAME ",'" XPATH_UPPER_TRANS "','" XPATH_LOWER_TRANS "') ='%s']" \
618 : "|/" PCMK_XE_CIB "/" PCMK_XE_CONFIGURATION "/" PCMK_XE_RESOURCES \
619 : "/" PCMK_XE_PRIMITIVE \
620 : "[@class='ocf'][@provider='pacemaker'][@type='remote'][translate(@id,'" XPATH_UPPER_TRANS "','" XPATH_LOWER_TRANS "') ='%s']" \
621 : "|/" PCMK_XE_CIB "/" PCMK_XE_CONFIGURATION "/" PCMK_XE_RESOURCES \
622 : "/" PCMK_XE_PRIMITIVE "/" PCMK_XE_META_ATTRIBUTES "/" PCMK_XE_NVPAIR \
623 : "[@name='" PCMK_META_REMOTE_NODE "'][translate(@value,'" XPATH_UPPER_TRANS "','" XPATH_LOWER_TRANS "') ='%s']" \
624 : "|/" PCMK_XE_CIB "/" PCMK_XE_STATUS "/" PCMK__XE_NODE_STATE \
625 : "[@" PCMK_XA_REMOTE_NODE "='true'][translate(@" PCMK_XA_ID ",'" XPATH_UPPER_TRANS "','" XPATH_LOWER_TRANS "') ='%s']"
626 :
627 : int
628 0 : query_node_uuid(cib_t * the_cib, const char *uname, char **uuid, int *is_remote_node)
629 : {
630 0 : int rc = pcmk_ok;
631 : char *xpath_string;
632 0 : xmlNode *xml_search = NULL;
633 0 : char *host_lowercase = NULL;
634 :
635 0 : CRM_ASSERT(uname != NULL);
636 :
637 0 : host_lowercase = g_ascii_strdown(uname, -1);
638 :
639 0 : if (uuid) {
640 0 : *uuid = NULL;
641 : }
642 0 : if (is_remote_node) {
643 0 : *is_remote_node = FALSE;
644 : }
645 :
646 0 : xpath_string = crm_strdup_printf(XPATH_NODE, host_lowercase, host_lowercase, host_lowercase, host_lowercase);
647 0 : if (cib_internal_op(the_cib, PCMK__CIB_REQUEST_QUERY, NULL, xpath_string,
648 : NULL, &xml_search,
649 : cib_sync_call|cib_scope_local|cib_xpath,
650 : NULL) == pcmk_ok) {
651 0 : rc = get_uuid_from_result(xml_search, uuid, is_remote_node);
652 : } else {
653 0 : rc = -ENXIO;
654 : }
655 0 : free(xpath_string);
656 0 : free_xml(xml_search);
657 0 : g_free(host_lowercase);
658 :
659 0 : if (rc != pcmk_ok) {
660 0 : crm_debug("Could not map node name '%s' to a UUID: %s",
661 : uname, pcmk_strerror(rc));
662 : } else {
663 0 : crm_info("Mapped node name '%s' to UUID %s", uname, (uuid? *uuid : ""));
664 : }
665 0 : return rc;
666 : }
667 :
668 : // Deprecated functions kept only for backward API compatibility
669 : // LCOV_EXCL_START
670 :
671 : #include <crm/cib/util_compat.h>
672 :
673 : int
674 : query_node_uname(cib_t * the_cib, const char *uuid, char **uname)
675 : {
676 : int rc = pcmk_ok;
677 : xmlNode *a_child = NULL;
678 : xmlNode *xml_obj = NULL;
679 : xmlNode *fragment = NULL;
680 : const char *child_name = NULL;
681 :
682 : CRM_ASSERT(uname != NULL);
683 : CRM_ASSERT(uuid != NULL);
684 :
685 : rc = the_cib->cmds->query(the_cib, PCMK_XE_NODES, &fragment,
686 : cib_sync_call | cib_scope_local);
687 : if (rc != pcmk_ok) {
688 : return rc;
689 : }
690 :
691 : xml_obj = fragment;
692 : CRM_CHECK(pcmk__xe_is(xml_obj, PCMK_XE_NODES), return -ENOMSG);
693 : crm_log_xml_trace(xml_obj, "Result section");
694 :
695 : rc = -ENXIO;
696 : *uname = NULL;
697 :
698 : for (a_child = pcmk__xe_first_child(xml_obj, PCMK_XE_NODE, NULL, NULL);
699 : a_child != NULL; a_child = pcmk__xe_next_same(a_child)) {
700 :
701 : child_name = pcmk__xe_id(a_child);
702 :
703 : if (pcmk__str_eq(uuid, child_name, pcmk__str_casei)) {
704 : child_name = crm_element_value(a_child, PCMK_XA_UNAME);
705 : if (child_name != NULL) {
706 : *uname = strdup(child_name);
707 : rc = pcmk_ok;
708 : }
709 : break;
710 : }
711 : }
712 :
713 : free_xml(fragment);
714 : return rc;
715 : }
716 :
717 : int
718 : set_standby(cib_t * the_cib, const char *uuid, const char *scope, const char *standby_value)
719 : {
720 : int rc = pcmk_ok;
721 : char *attr_id = NULL;
722 :
723 : CRM_CHECK(uuid != NULL, return -EINVAL);
724 : CRM_CHECK(standby_value != NULL, return -EINVAL);
725 :
726 : if (pcmk__strcase_any_of(scope, "reboot", PCMK_XE_STATUS, NULL)) {
727 : scope = PCMK_XE_STATUS;
728 : attr_id = crm_strdup_printf("transient-standby-%.256s", uuid);
729 :
730 : } else {
731 : scope = PCMK_XE_NODES;
732 : attr_id = crm_strdup_printf("standby-%.256s", uuid);
733 : }
734 :
735 : rc = update_attr_delegate(the_cib, cib_sync_call, scope, uuid, NULL, NULL,
736 : attr_id, PCMK_NODE_ATTR_STANDBY, standby_value,
737 : TRUE, NULL, NULL);
738 :
739 : free(attr_id);
740 : return rc;
741 : }
742 :
743 : // LCOV_EXCL_STOP
744 : // End deprecated API
|