This source file includes following definitions.
- PCMK__OUTPUT_ARGS
- delete_cb
- promotion_cb
- update_cb
- utilization_cb
- value_cb
- wait_cb
- get_node_name_from_local
- send_attrd_update
- delete_attr_on_node
- command_delete
- update_attr_on_node
- command_update
- output_one_attribute
- command_query
- set_type
- use_attrd
- try_ipc_update
- pattern_used_correctly
- delete_used_correctly
- build_arg_context
- main
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdint.h>
13 #include <stdio.h>
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <libgen.h>
19 #include <time.h>
20
21 #include <sys/param.h>
22 #include <sys/types.h>
23
24 #include <crm/crm.h>
25 #include <crm/msg_xml.h>
26 #include <crm/common/xml.h>
27 #include <crm/common/ipc.h>
28 #include <crm/common/util.h>
29 #include <crm/cluster.h>
30
31 #include <crm/cib.h>
32 #include <crm/cib/internal.h>
33 #include <crm/common/attrd_internal.h>
34 #include <crm/common/cmdline_internal.h>
35 #include <crm/common/ipc_attrd_internal.h>
36 #include <crm/common/ipc_controld.h>
37 #include <crm/common/output_internal.h>
38 #include <sys/utsname.h>
39
40 #include <pacemaker-internal.h>
41
42 #define SUMMARY "crm_attribute - query and update Pacemaker cluster options and node attributes"
43
44 GError *error = NULL;
45 crm_exit_t exit_code = CRM_EX_OK;
46 uint64_t cib_opts = cib_sync_call;
47
48 PCMK__OUTPUT_ARGS("attribute", "const char *", "const char *", "const char *",
49 "const char *", "const char *")
50 static int
51 attribute_text(pcmk__output_t *out, va_list args)
52 {
53 const char *scope = va_arg(args, const char *);
54 const char *instance = va_arg(args, const char *);
55 const char *name = va_arg(args, const char *);
56 const char *value = va_arg(args, const char *);
57 const char *host G_GNUC_UNUSED = va_arg(args, const char *);
58
59 if (out->quiet) {
60 if (value != NULL) {
61 pcmk__formatted_printf(out, "%s\n", value);
62 }
63 } else {
64 out->info(out, "%s%s %s%s %s%s value=%s",
65 scope ? "scope=" : "", scope ? scope : "",
66 instance ? "id=" : "", instance ? instance : "",
67 name ? "name=" : "", name ? name : "",
68 value ? value : "(null)");
69 }
70
71 return pcmk_rc_ok;
72 }
73
74 static pcmk__supported_format_t formats[] = {
75 PCMK__SUPPORTED_FORMAT_NONE,
76 PCMK__SUPPORTED_FORMAT_TEXT,
77 PCMK__SUPPORTED_FORMAT_XML,
78 { NULL, NULL, NULL }
79 };
80
81 static pcmk__message_entry_t fmt_functions[] = {
82 { "attribute", "text", attribute_text },
83
84 { NULL, NULL, NULL }
85 };
86
87 struct {
88 char command;
89 gchar *attr_default;
90 gchar *attr_id;
91 gchar *attr_name;
92 uint32_t attr_options;
93 gchar *attr_pattern;
94 char *attr_value;
95 char *dest_node;
96 gchar *dest_uname;
97 gboolean inhibit;
98 gchar *set_name;
99 char *set_type;
100 gchar *type;
101 gboolean promotion_score;
102 } options = {
103 .command = 'G',
104 .promotion_score = FALSE
105 };
106
107 #define INDENT " "
108
109 static gboolean
110 delete_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
111 options.command = 'D';
112 pcmk__str_update(&options.attr_value, NULL);
113 return TRUE;
114 }
115
116 static gboolean
117 promotion_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
118 char *score_name = NULL;
119
120 options.promotion_score = TRUE;
121
122 if (options.attr_name) {
123 g_free(options.attr_name);
124 }
125
126 score_name = pcmk_promotion_score_name(optarg);
127 if (score_name != NULL) {
128 options.attr_name = g_strdup(score_name);
129 free(score_name);
130 } else {
131 options.attr_name = NULL;
132 }
133
134 return TRUE;
135 }
136
137 static gboolean
138 update_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
139 options.command = 'u';
140 pcmk__str_update(&options.attr_value, optarg);
141 return TRUE;
142 }
143
144 static gboolean
145 utilization_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
146 if (options.type) {
147 g_free(options.type);
148 }
149
150 options.type = g_strdup(XML_CIB_TAG_NODES);
151 pcmk__str_update(&options.set_type, XML_TAG_UTILIZATION);
152 return TRUE;
153 }
154
155 static gboolean
156 value_cb(const gchar *option_name, const gchar *optarg, gpointer data, GError **error) {
157 options.command = 'G';
158 pcmk__str_update(&options.attr_value, NULL);
159 return TRUE;
160 }
161
162 static gboolean
163 wait_cb (const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
164 if (pcmk__str_eq(optarg, "no", pcmk__str_none)) {
165 pcmk__clear_node_attr_flags(options.attr_options, pcmk__node_attr_sync_local | pcmk__node_attr_sync_cluster);
166 return TRUE;
167 } else if (pcmk__str_eq(optarg, PCMK__VALUE_LOCAL, pcmk__str_none)) {
168 pcmk__clear_node_attr_flags(options.attr_options, pcmk__node_attr_sync_local | pcmk__node_attr_sync_cluster);
169 pcmk__set_node_attr_flags(options.attr_options, pcmk__node_attr_sync_local);
170 return TRUE;
171 } else if (pcmk__str_eq(optarg, PCMK__VALUE_CLUSTER, pcmk__str_none)) {
172 pcmk__clear_node_attr_flags(options.attr_options, pcmk__node_attr_sync_local | pcmk__node_attr_sync_cluster);
173 pcmk__set_node_attr_flags(options.attr_options, pcmk__node_attr_sync_cluster);
174 return TRUE;
175 } else {
176 g_set_error(err, PCMK__EXITC_ERROR, CRM_EX_USAGE,
177 "--wait= must be one of 'no', 'local', 'cluster'");
178 return FALSE;
179 }
180 }
181
182 static GOptionEntry selecting_entries[] = {
183 { "id", 'i', 0, G_OPTION_ARG_STRING, &options.attr_id,
184 "(Advanced) Operate on instance of specified attribute with this\n"
185 INDENT "XML ID",
186 "XML_ID"
187 },
188
189 { "name", 'n', 0, G_OPTION_ARG_STRING, &options.attr_name,
190 "Operate on attribute or option with this name. For queries, this\n"
191 INDENT "is optional, in which case all matching attributes will be\n"
192 INDENT "returned.",
193 "NAME"
194 },
195
196 { "pattern", 'P', 0, G_OPTION_ARG_STRING, &options.attr_pattern,
197 "Operate on all attributes matching this pattern\n"
198 INDENT "(with -v, -D, or -G)",
199 "PATTERN"
200 },
201
202 { "promotion", 'p', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, promotion_cb,
203 "Operate on node attribute used as promotion score for specified\n"
204 INDENT "resource, or resource given in OCF_RESOURCE_INSTANCE environment\n"
205 INDENT "variable if none is specified; this also defaults -l/--lifetime\n"
206 INDENT "to reboot (normally invoked from an OCF resource agent)",
207 "RESOURCE"
208 },
209
210 { "set-name", 's', 0, G_OPTION_ARG_STRING, &options.set_name,
211 "(Advanced) Operate on instance of specified attribute that is\n"
212 INDENT "within set with this XML ID",
213 "NAME"
214 },
215
216 { NULL }
217 };
218
219 static GOptionEntry command_entries[] = {
220 { "delete", 'D', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, delete_cb,
221 "Delete the attribute/option",
222 NULL
223 },
224
225 { "query", 'G', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, value_cb,
226 "Query the current value of the attribute/option.\n"
227 INDENT "See also: -n, -P",
228 NULL
229 },
230
231 { "update", 'v', 0, G_OPTION_ARG_CALLBACK, update_cb,
232 "Update the value of the attribute/option",
233 "VALUE"
234 },
235
236 { NULL }
237 };
238
239 static GOptionEntry addl_entries[] = {
240 { "default", 'd', 0, G_OPTION_ARG_STRING, &options.attr_default,
241 "(Advanced) Default value to display if none is found in configuration",
242 "VALUE"
243 },
244
245 { "lifetime", 'l', 0, G_OPTION_ARG_STRING, &options.type,
246 "Lifetime of the node attribute.\n"
247 INDENT "Valid values: reboot, forever",
248 "LIFETIME"
249 },
250
251 { "node", 'N', 0, G_OPTION_ARG_STRING, &options.dest_uname,
252 "Set a node attribute for named node (instead of a cluster option).\n"
253 INDENT "See also: -l",
254 "NODE"
255 },
256
257 { "type", 't', 0, G_OPTION_ARG_STRING, &options.type,
258 "Which part of the configuration to update/delete/query the option in.\n"
259 INDENT "Valid values: crm_config, rsc_defaults, op_defaults, tickets",
260 "SECTION"
261 },
262
263 { "wait", 'W', 0, G_OPTION_ARG_CALLBACK, wait_cb,
264 "Wait for some event to occur before returning. Values are 'no' (wait\n"
265 INDENT "only for the attribute daemon to acknowledge the request),\n"
266 INDENT "'local' (wait until the change has propagated to where a local\n"
267 INDENT "query will return the request value, or the value set by a\n"
268 INDENT "later request), or 'cluster' (wait until the change has propagated\n"
269 INDENT "to where a query anywhere on the cluster will return the requested\n"
270 INDENT "value, or the value set by a later request). Default is 'no'.\n"
271 INDENT "(with -N, and one of -D or -u)",
272 "UNTIL" },
273
274 { "utilization", 'z', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, utilization_cb,
275 "Set an utilization attribute for the node.",
276 NULL
277 },
278
279 { "inhibit-policy-engine", '!', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &options.inhibit,
280 NULL, NULL
281 },
282
283 { NULL }
284 };
285
286 static GOptionEntry deprecated_entries[] = {
287 { "attr-id", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &options.attr_id,
288 NULL, NULL
289 },
290
291 { "attr-name", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &options.attr_name,
292 NULL, NULL
293 },
294
295 { "attr-value", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, update_cb,
296 NULL, NULL
297 },
298
299 { "delete-attr", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, delete_cb,
300 NULL, NULL
301 },
302
303 { "get-value", 0, G_OPTION_FLAG_HIDDEN|G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, value_cb,
304 NULL, NULL
305 },
306
307 { "node-uname", 'U', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &options.dest_uname,
308 NULL, NULL
309 },
310
311 { NULL }
312 };
313
314 static void
315 get_node_name_from_local(void)
316 {
317 char *hostname = pcmk_hostname();
318
319 g_free(options.dest_uname);
320
321
322
323
324
325 options.dest_uname = g_strdup(hostname);
326 free(hostname);
327 }
328
329 static int
330 send_attrd_update(char command, const char *attr_node, const char *attr_name,
331 const char *attr_value, const char *attr_set,
332 const char *attr_dampen, uint32_t attr_options)
333 {
334 int rc = pcmk_rc_ok;
335 uint32_t opts = attr_options;
336
337 switch (command) {
338 case 'D':
339 rc = pcmk__attrd_api_delete(NULL, attr_node, attr_name, opts);
340 break;
341
342 case 'u':
343 rc = pcmk__attrd_api_update(NULL, attr_node, attr_name,
344 attr_value, NULL, attr_set, NULL,
345 opts | pcmk__node_attr_value);
346 break;
347 }
348
349 if (rc != pcmk_rc_ok) {
350 g_set_error(&error, PCMK__RC_ERROR, rc, "Could not update %s=%s: %s (%d)",
351 attr_name, attr_value, pcmk_rc_str(rc), rc);
352 }
353
354 return rc;
355 }
356
357 struct delete_data_s {
358 pcmk__output_t *out;
359 cib_t *cib;
360 };
361
362 static int
363 delete_attr_on_node(xmlNode *child, void *userdata)
364 {
365 struct delete_data_s *dd = (struct delete_data_s *) userdata;
366
367 const char *attr_name = crm_element_value(child, XML_NVPAIR_ATTR_NAME);
368 int rc = pcmk_rc_ok;
369
370 if (!pcmk__str_eq(attr_name, options.attr_pattern, pcmk__str_regex)) {
371 return pcmk_rc_ok;
372 }
373
374 rc = cib__delete_node_attr(dd->out, dd->cib, cib_opts, options.type,
375 options.dest_node, options.set_type,
376 options.set_name, options.attr_id,
377 attr_name, options.attr_value, NULL);
378
379 if (rc == ENXIO) {
380 rc = pcmk_rc_ok;
381 }
382
383 return rc;
384 }
385
386 static int
387 command_delete(pcmk__output_t *out, cib_t *cib)
388 {
389 int rc = pcmk_rc_ok;
390
391 xmlNode *result = NULL;
392 bool use_pattern = options.attr_pattern != NULL;
393
394
395 if (use_pattern) {
396 struct delete_data_s dd = { out, cib };
397
398 rc = cib__get_node_attrs(out, cib, options.type, options.dest_node,
399 options.set_type, options.set_name, NULL, NULL,
400 NULL, &result);
401
402 if (rc != pcmk_rc_ok) {
403 goto done_deleting;
404 }
405
406 rc = pcmk__xe_foreach_child(result, NULL, delete_attr_on_node, &dd);
407
408 if (rc != pcmk_rc_ok) {
409 goto done_deleting;
410 }
411
412 } else {
413 rc = cib__delete_node_attr(out, cib, cib_opts, options.type, options.dest_node,
414 options.set_type, options.set_name, options.attr_id,
415 options.attr_name, options.attr_value, NULL);
416 }
417
418 done_deleting:
419 free_xml(result);
420
421 if (rc == ENXIO) {
422
423
424
425
426 rc = pcmk_rc_ok;
427 }
428
429 return rc;
430 }
431
432 struct update_data_s {
433 pcmk__output_t *out;
434 cib_t *cib;
435 int is_remote_node;
436 };
437
438 static int
439 update_attr_on_node(xmlNode *child, void *userdata)
440 {
441 struct update_data_s *ud = (struct update_data_s *) userdata;
442
443 const char *attr_name = crm_element_value(child, XML_NVPAIR_ATTR_NAME);
444
445 if (!pcmk__str_eq(attr_name, options.attr_pattern, pcmk__str_regex)) {
446 return pcmk_rc_ok;
447 }
448
449 return cib__update_node_attr(ud->out, ud->cib, cib_opts, options.type,
450 options.dest_node, options.set_type,
451 options.set_name, options.attr_id,
452 attr_name, options.attr_value, NULL,
453 ud->is_remote_node ? "remote" : NULL);
454 }
455
456 static int
457 command_update(pcmk__output_t *out, cib_t *cib, int is_remote_node)
458 {
459 int rc = pcmk_rc_ok;
460
461 xmlNode *result = NULL;
462 bool use_pattern = options.attr_pattern != NULL;
463
464 CRM_LOG_ASSERT(options.type != NULL);
465 CRM_LOG_ASSERT(options.attr_name != NULL);
466 CRM_LOG_ASSERT(options.attr_value != NULL);
467
468
469 if (use_pattern) {
470 struct update_data_s ud = { out, cib, is_remote_node };
471
472 rc = cib__get_node_attrs(out, cib, options.type, options.dest_node,
473 options.set_type, options.set_name, NULL, NULL,
474 NULL, &result);
475
476 if (rc != pcmk_rc_ok) {
477 goto done_updating;
478 }
479
480 rc = pcmk__xe_foreach_child(result, NULL, update_attr_on_node, &ud);
481
482 if (rc != pcmk_rc_ok) {
483 goto done_updating;
484 }
485
486 } else {
487 rc = cib__update_node_attr(out, cib, cib_opts, options.type,
488 options.dest_node, options.set_type,
489 options.set_name, options.attr_id,
490 options.attr_name, options.attr_value,
491 NULL, is_remote_node ? "remote" : NULL);
492 }
493
494 done_updating:
495 free_xml(result);
496 return rc;
497 }
498
499 struct output_data_s {
500 pcmk__output_t *out;
501 bool use_pattern;
502 bool did_output;
503 };
504
505 static int
506 output_one_attribute(xmlNode *node, void *userdata)
507 {
508 struct output_data_s *od = (struct output_data_s *) userdata;
509
510 const char *name = crm_element_value(node, XML_NVPAIR_ATTR_NAME);
511 const char *value = crm_element_value(node, XML_NVPAIR_ATTR_VALUE);
512 const char *host = crm_element_value(node, PCMK__XA_ATTR_NODE_NAME);
513
514 const char *type = options.type;
515 const char *attr_id = options.attr_id;
516
517 if (od->use_pattern && !pcmk__str_eq(name, options.attr_pattern, pcmk__str_regex)) {
518 return pcmk_rc_ok;
519 }
520
521 od->out->message(od->out, "attribute", type, attr_id, name, value, host);
522 od->did_output = true;
523 crm_info("Read %s='%s' %s%s",
524 pcmk__s(name, "<null>"), pcmk__s(value, ""),
525 options.set_name ? "in " : "", options.set_name ? options.set_name : "");
526
527 return pcmk_rc_ok;
528 }
529
530 static int
531 command_query(pcmk__output_t *out, cib_t *cib)
532 {
533 int rc = pcmk_rc_ok;
534
535 xmlNode *result = NULL;
536 bool use_pattern = options.attr_pattern != NULL;
537
538
539
540
541
542
543 if (use_pattern) {
544 rc = cib__get_node_attrs(out, cib, options.type, options.dest_node,
545 options.set_type, options.set_name, NULL,
546 NULL, NULL, &result);
547 } else {
548 rc = cib__get_node_attrs(out, cib, options.type, options.dest_node,
549 options.set_type, options.set_name, options.attr_id,
550 options.attr_name, NULL, &result);
551 }
552
553 if (rc == ENXIO && options.attr_default) {
554
555 const char *type = options.type;
556 const char *attr_id = options.attr_id;
557 const char *attr_name = options.attr_name;
558 const char *attr_default = options.attr_default;
559 const char *dest_uname = options.dest_uname;
560
561 out->message(out, "attribute", type, attr_id, attr_name, attr_default,
562 dest_uname);
563 rc = pcmk_rc_ok;
564
565 } else if (rc != pcmk_rc_ok) {
566
567
568 } else if (xml_has_children(result)) {
569 struct output_data_s od = { out, use_pattern, false };
570
571 pcmk__xe_foreach_child(result, NULL, output_one_attribute, &od);
572
573 if (!od.did_output) {
574 rc = ENXIO;
575 }
576
577 } else {
578 struct output_data_s od = { out, use_pattern, false };
579 output_one_attribute(result, &od);
580 }
581
582 free_xml(result);
583 return rc;
584 }
585
586 static void
587 set_type(void)
588 {
589 if (options.type == NULL) {
590 if (options.promotion_score) {
591
592 options.type = g_strdup(XML_CIB_TAG_STATUS);
593
594 } else if (options.dest_uname != NULL) {
595
596 options.type = g_strdup(XML_CIB_TAG_NODES);
597
598 } else {
599
600 options.type = g_strdup(XML_CIB_TAG_CRMCONFIG);
601 }
602
603 } else if (pcmk__str_eq(options.type, "reboot", pcmk__str_casei)) {
604 options.type = g_strdup(XML_CIB_TAG_STATUS);
605
606 } else if (pcmk__str_eq(options.type, "forever", pcmk__str_casei)) {
607 options.type = g_strdup(XML_CIB_TAG_NODES);
608 }
609 }
610
611 static bool
612 use_attrd(void)
613 {
614
615
616
617 return pcmk__str_eq(options.type, XML_CIB_TAG_STATUS, pcmk__str_casei) &&
618 getenv("CIB_file") == NULL && getenv("CIB_shadow") == NULL;
619 }
620
621 static bool
622 try_ipc_update(void)
623 {
624 return use_attrd() && (options.command == 'D' || options.command == 'u');
625 }
626
627 static bool
628 pattern_used_correctly(void)
629 {
630
631
632
633 return options.command == 'G' || options.command == 'u' || options.command == 'D';
634 }
635
636 static bool
637 delete_used_correctly(void)
638 {
639 return options.command != 'D' || options.attr_name != NULL || options.attr_pattern != NULL;
640 }
641
642 static GOptionContext *
643 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
644 GOptionContext *context = NULL;
645
646 GOptionEntry extra_prog_entries[] = {
647 { "quiet", 'q', 0, G_OPTION_ARG_NONE, &(args->quiet),
648 "Print only the value on stdout",
649 NULL },
650
651 { "quiet", 'Q', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &(args->quiet),
652 NULL, NULL
653 },
654
655 { NULL }
656 };
657
658 const char *description = "Examples:\n\n"
659 "Add new node attribute called 'location' with the value of 'office' for host 'myhost':\n\n"
660 "\tcrm_attribute --node myhost --name location --update office\n\n"
661 "Query the value of the 'location' node attribute for host 'myhost':\n\n"
662 "\tcrm_attribute --node myhost --name location --query\n\n"
663 "Change the value of the 'location' node attribute for host 'myhost':\n\n"
664 "\tcrm_attribute --node myhost --name location --update backoffice\n\n"
665 "Delete the 'location' node attribute for host 'myhost':\n\n"
666 "\tcrm_attribute --node myhost --name location --delete\n\n"
667 "Query the value of the 'cluster-delay' cluster option:\n\n"
668 "\tcrm_attribute --type crm_config --name cluster-delay --query\n\n"
669 "Query value of the 'cluster-delay' cluster option and print only the value:\n\n"
670 "\tcrm_attribute --type crm_config --name cluster-delay --query --quiet\n\n";
671
672 context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
673 pcmk__add_main_args(context, extra_prog_entries);
674 g_option_context_set_description(context, description);
675
676 pcmk__add_arg_group(context, "selections", "Selecting attributes:",
677 "Show selecting options", selecting_entries);
678 pcmk__add_arg_group(context, "command", "Commands:",
679 "Show command options", command_entries);
680 pcmk__add_arg_group(context, "additional", "Additional options:",
681 "Show additional options", addl_entries);
682 pcmk__add_arg_group(context, "deprecated", "Deprecated Options:",
683 "Show deprecated options", deprecated_entries);
684
685 return context;
686 }
687
688 int
689 main(int argc, char **argv)
690 {
691 cib_t *the_cib = NULL;
692 int is_remote_node = 0;
693
694 int rc = pcmk_rc_ok;
695
696 pcmk__output_t *out = NULL;
697
698 GOptionGroup *output_group = NULL;
699 pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
700 gchar **processed_args = pcmk__cmdline_preproc(argv, "NPUdilnpstv");
701 GOptionContext *context = build_arg_context(args, &output_group);
702
703 pcmk__register_formats(output_group, formats);
704 if (!g_option_context_parse_strv(context, &processed_args, &error)) {
705 exit_code = CRM_EX_USAGE;
706 goto done;
707 }
708
709 pcmk__cli_init_logging("crm_attribute", args->verbosity);
710
711 rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
712 if (rc != pcmk_rc_ok) {
713 exit_code = CRM_EX_ERROR;
714 g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s",
715 args->output_ty, pcmk_rc_str(rc));
716 goto done;
717 }
718
719 pcmk__register_lib_messages(out);
720 pcmk__register_messages(out, fmt_functions);
721
722 if (args->version) {
723 out->version(out, false);
724 goto done;
725 }
726
727 out->quiet = args->quiet;
728
729 if (options.promotion_score && options.attr_name == NULL) {
730 exit_code = CRM_EX_USAGE;
731 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
732 "-p/--promotion must be called from an OCF resource agent "
733 "or with a resource ID specified");
734 goto done;
735 }
736
737 if (options.inhibit) {
738 crm_warn("Inhibiting notifications for this update");
739 cib__set_call_options(cib_opts, crm_system_name, cib_inhibit_notify);
740 }
741
742 the_cib = cib_new();
743 rc = the_cib->cmds->signon(the_cib, crm_system_name, cib_command);
744 rc = pcmk_legacy2rc(rc);
745
746 if (rc != pcmk_rc_ok) {
747 exit_code = pcmk_rc2exitc(rc);
748 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
749 "Could not connect to the CIB: %s", pcmk_rc_str(rc));
750 goto done;
751 }
752
753 set_type();
754
755
756 if (!pcmk__strcase_any_of(options.type, XML_CIB_TAG_CRMCONFIG, XML_CIB_TAG_TICKETS,
757 NULL)) {
758
759
760
761
762 const char *target = pcmk__node_attr_target(options.dest_uname);
763
764 if (target != NULL) {
765 g_free(options.dest_uname);
766 options.dest_uname = g_strdup(target);
767 } else if (getenv("CIB_file") != NULL && options.dest_uname == NULL) {
768 get_node_name_from_local();
769 }
770
771 if (options.dest_uname == NULL) {
772 char *node_name = NULL;
773
774 rc = pcmk__query_node_name(out, 0, &node_name, 0);
775
776 if (rc != pcmk_rc_ok) {
777 exit_code = pcmk_rc2exitc(rc);
778 free(node_name);
779 goto done;
780 }
781 options.dest_uname = g_strdup(node_name);
782 free(node_name);
783 }
784
785 rc = query_node_uuid(the_cib, options.dest_uname, &options.dest_node, &is_remote_node);
786 rc = pcmk_legacy2rc(rc);
787
788 if (rc != pcmk_rc_ok) {
789 exit_code = pcmk_rc2exitc(rc);
790 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
791 "Could not map name=%s to a UUID", options.dest_uname);
792 goto done;
793 }
794 }
795
796 if (!delete_used_correctly()) {
797 exit_code = CRM_EX_USAGE;
798 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
799 "Error: must specify attribute name or pattern to delete");
800 goto done;
801 }
802
803 if (options.attr_pattern) {
804 if (options.attr_name) {
805 exit_code = CRM_EX_USAGE;
806 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
807 "Error: --name and --pattern cannot be used at the same time");
808 goto done;
809 }
810
811 if (!pattern_used_correctly()) {
812 exit_code = CRM_EX_USAGE;
813 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
814 "Error: pattern can only be used with delete, query, or update");
815 goto done;
816 }
817
818 g_free(options.attr_name);
819 options.attr_name = options.attr_pattern;
820 options.attr_options |= pcmk__node_attr_pattern;
821 }
822
823 if (is_remote_node) {
824 options.attr_options |= pcmk__node_attr_remote;
825 }
826
827 if (pcmk__str_eq(options.set_type, XML_TAG_UTILIZATION, pcmk__str_none)) {
828 options.attr_options |= pcmk__node_attr_utilization;
829 }
830
831 if (try_ipc_update() &&
832 (send_attrd_update(options.command, options.dest_uname, options.attr_name,
833 options.attr_value, options.set_name, NULL, options.attr_options) == pcmk_rc_ok)) {
834 crm_info("Update %s=%s sent via pacemaker-attrd",
835 options.attr_name, ((options.command == 'D')? "<none>" : options.attr_value));
836
837 } else if (options.command == 'D') {
838 rc = command_delete(out, the_cib);
839
840 } else if (options.command == 'u') {
841 rc = command_update(out, the_cib, is_remote_node);
842
843 } else {
844 rc = command_query(out, the_cib);
845 }
846
847 if (rc == ENOTUNIQ) {
848 exit_code = pcmk_rc2exitc(rc);
849 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
850 "Please choose from one of the matches below and supply the 'id' with --attr-id");
851
852 } else if (rc != pcmk_rc_ok) {
853 exit_code = pcmk_rc2exitc(rc);
854 g_set_error(&error, PCMK__EXITC_ERROR, exit_code,
855 "Error performing operation: %s", pcmk_strerror(rc));
856 }
857
858 done:
859 g_strfreev(processed_args);
860 pcmk__free_arg_context(context);
861
862 free(options.attr_default);
863 g_free(options.attr_id);
864 g_free(options.attr_name);
865 free(options.attr_value);
866 free(options.dest_node);
867 g_free(options.dest_uname);
868 g_free(options.set_name);
869 free(options.set_type);
870 g_free(options.type);
871
872 cib__clean_up_connection(&the_cib);
873
874 pcmk__output_and_clear_error(&error, out);
875
876 if (out != NULL) {
877 out->finish(out, exit_code, true, NULL);
878 pcmk__output_free(out);
879 }
880
881 pcmk__unregister_formats();
882 return crm_exit(exit_code);
883 }