This source file includes following definitions.
- main
- send_attrd_query
- validate_attrd_reply
- print_attrd_values
- do_query
- do_update
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <libgen.h>
16
17 #include <sys/param.h>
18 #include <sys/types.h>
19
20 #include <crm/crm.h>
21 #include <crm/msg_xml.h>
22 #include <crm/common/xml_internal.h>
23 #include <crm/common/ipc.h>
24
25 #include <crm/common/attrd_internal.h>
26
27 static pcmk__cli_option_t long_options[] = {
28
29 {
30 "help", no_argument, NULL, '?',
31 "\tThis text", pcmk__option_default
32 },
33 {
34 "version", no_argument, NULL, '$',
35 "\tVersion information", pcmk__option_default
36 },
37 {
38 "verbose", no_argument, NULL, 'V',
39 "\tIncrease debug output\n", pcmk__option_default
40 },
41 {
42 "name", required_argument, NULL, 'n',
43 "The attribute's name", pcmk__option_default
44 },
45 {
46 "-spacer-", no_argument, NULL, '-',
47 "\nCommands:", pcmk__option_default
48 },
49 {
50 "update", required_argument, NULL, 'U',
51 "Update attribute's value in pacemaker-attrd. If this causes the value "
52 "to change, it will also be updated in the cluster configuration.",
53 pcmk__option_default
54 },
55 {
56 "update-both", required_argument, NULL, 'B',
57 "Update attribute's value and time to wait (dampening) in "
58 "pacemaker-attrd. If this causes the value or dampening to change, "
59 "the attribute will also be written to the cluster configuration, "
60 "so be aware that repeatedly changing the dampening reduces its "
61 "effectiveness.",
62 pcmk__option_default
63 },
64 {
65 "update-delay", no_argument, NULL, 'Y',
66 "Update attribute's dampening in pacemaker-attrd (requires "
67 "-d/--delay). If this causes the dampening to change, the "
68 "attribute will also be written to the cluster configuration, so "
69 "be aware that repeatedly changing the dampening reduces its "
70 "effectiveness.",
71 pcmk__option_default
72 },
73 {
74 "query", no_argument, NULL, 'Q',
75 "\tQuery the attribute's value from pacemaker-attrd",
76 pcmk__option_default
77 },
78 {
79 "delete", no_argument, NULL, 'D',
80 "\tDelete attribute from pacemaker-attrd. If a value was previously "
81 "set, it will also be removed from the cluster configuration",
82 pcmk__option_default
83 },
84 {
85 "refresh", no_argument, NULL, 'R',
86 "\t(Advanced) Force the pacemaker-attrd daemon to resend all current "
87 "values to the CIB",
88 pcmk__option_default
89 },
90
91 {
92 "-spacer-", no_argument, NULL, '-',
93 "\nAdditional options:", pcmk__option_default
94 },
95 {
96 "delay", required_argument, NULL, 'd',
97 "The time to wait (dampening) in seconds for further changes "
98 "before writing",
99 pcmk__option_default
100 },
101 {
102 "set", required_argument, NULL, 's',
103 "(Advanced) The attribute set in which to place the value",
104 pcmk__option_default
105 },
106 {
107 "node", required_argument, NULL, 'N',
108 "Set the attribute for the named node (instead of the local one)",
109 pcmk__option_default
110 },
111 {
112 "all", no_argument, NULL, 'A',
113 "Show values of the attribute for all nodes (query only)",
114 pcmk__option_default
115 },
116
117
118 {
119 "lifetime", required_argument, NULL, 'l',
120 "(Not yet implemented) Lifetime of the node attribute (silently "
121 "ignored by cluster)",
122 pcmk__option_default
123 },
124 {
125 "private", no_argument, NULL, 'p',
126 "\tIf this creates a new attribute, never write the attribute to CIB",
127 pcmk__option_default
128 },
129
130
131 {
132 "quiet", no_argument, NULL, 'q',
133 NULL, pcmk__option_hidden
134 },
135 {
136 "update", required_argument, NULL, 'v',
137 NULL, pcmk__option_hidden
138 },
139 {
140 "section", required_argument, NULL, 'S',
141 NULL, pcmk__option_hidden
142 },
143 { 0, 0, 0, 0 }
144 };
145
146 static int do_query(const char *attr_name, const char *attr_node, gboolean query_all);
147 static int do_update(char command, const char *attr_node, const char *attr_name,
148 const char *attr_value, const char *attr_section,
149 const char *attr_set, const char *attr_dampen, int attr_options);
150
151
152 #define cleanup_memory() \
153 free(attr_dampen); \
154 free(attr_name); \
155 free(attr_node); \
156 free(attr_section); \
157 free(attr_set);
158
159 #define set_option(option_var) \
160 if (option_var) { \
161 free(option_var); \
162 } \
163 option_var = strdup(optarg);
164
165 int
166 main(int argc, char **argv)
167 {
168 int index = 0;
169 int argerr = 0;
170 int attr_options = pcmk__node_attr_none;
171 int flag;
172 crm_exit_t exit_code = CRM_EX_OK;
173 char *attr_node = NULL;
174 char *attr_name = NULL;
175 char *attr_set = NULL;
176 char *attr_section = NULL;
177 char *attr_dampen = NULL;
178 const char *attr_value = NULL;
179 char command = 'Q';
180
181 gboolean query_all = FALSE;
182
183 pcmk__cli_init_logging("attrd_updater", 0);
184 pcmk__set_cli_options(NULL, "-n <attribute> <command> [options]",
185 long_options,
186 "query and update Pacemaker node attributes");
187
188 if (argc < 2) {
189 pcmk__cli_help('?', CRM_EX_USAGE);
190 }
191
192 while (1) {
193 flag = pcmk__next_cli_option(argc, argv, &index, NULL);
194 if (flag == -1)
195 break;
196
197 switch (flag) {
198 case 'V':
199 crm_bump_log_level(argc, argv);
200 break;
201 case '?':
202 case '$':
203 cleanup_memory();
204 pcmk__cli_help(flag, CRM_EX_OK);
205 break;
206 case 'n':
207 set_option(attr_name);
208 break;
209 case 's':
210 set_option(attr_set);
211 break;
212 case 'd':
213 set_option(attr_dampen);
214 break;
215 case 'l':
216 case 'S':
217 set_option(attr_section);
218 break;
219 case 'N':
220 set_option(attr_node);
221 break;
222 case 'A':
223 query_all = TRUE;
224 break;
225 case 'p':
226 pcmk__set_node_attr_flags(attr_options, pcmk__node_attr_private);
227 break;
228 case 'q':
229 break;
230 case 'Y':
231 command = flag;
232 crm_log_args(argc, argv);
233 break;
234 case 'Q':
235 case 'B':
236 case 'R':
237 case 'D':
238 case 'U':
239 case 'v':
240 command = flag;
241 attr_value = optarg;
242 crm_log_args(argc, argv);
243 break;
244 default:
245 ++argerr;
246 break;
247 }
248 }
249
250 if (optind > argc) {
251 ++argerr;
252 }
253
254 if (command != 'R' && attr_name == NULL) {
255 ++argerr;
256 }
257
258 if (argerr) {
259 cleanup_memory();
260 pcmk__cli_help('?', CRM_EX_USAGE);
261 }
262
263 if (command == 'Q') {
264 exit_code = crm_errno2exit(do_query(attr_name, attr_node, query_all));
265 } else {
266
267
268
269
270
271 const char *target = pcmk__node_attr_target(attr_node);
272
273 exit_code = pcmk_rc2exitc(do_update(command,
274 target == NULL ? attr_node : target,
275 attr_name, attr_value,
276 attr_section, attr_set,
277 attr_dampen, attr_options));
278 }
279
280 cleanup_memory();
281 crm_exit(exit_code);
282 }
283
284
285
286
287
288
289
290
291
292
293
294
295 static int
296 send_attrd_query(const char *name, const char *host, xmlNode **reply)
297 {
298 int rc;
299 crm_ipc_t *ipc;
300 xmlNode *query;
301
302
303 query = create_xml_node(NULL, __func__);
304 if (query == NULL) {
305 return -ENOMEM;
306 }
307 crm_xml_add(query, F_TYPE, T_ATTRD);
308 crm_xml_add(query, F_ORIG, crm_system_name);
309 crm_xml_add(query, PCMK__XA_ATTR_NODE_NAME, host);
310 crm_xml_add(query, PCMK__XA_TASK, PCMK__ATTRD_CMD_QUERY);
311 crm_xml_add(query, PCMK__XA_ATTR_NAME, name);
312
313
314 crm_debug("Sending query for value of %s on %s", name, (host? host : "all nodes"));
315 ipc = crm_ipc_new(T_ATTRD, 0);
316 if (crm_ipc_connect(ipc) == FALSE) {
317 crm_perror(LOG_ERR, "Connection to cluster attribute manager failed");
318 rc = -ENOTCONN;
319 } else {
320 rc = crm_ipc_send(ipc, query, crm_ipc_client_response, 0, reply);
321 if (rc > 0) {
322 rc = pcmk_ok;
323 }
324 crm_ipc_close(ipc);
325 }
326 crm_ipc_destroy(ipc);
327
328 free_xml(query);
329 return(rc);
330 }
331
332
333
334
335
336
337
338
339
340
341 static int
342 validate_attrd_reply(xmlNode *reply, const char *attr_name)
343 {
344 const char *reply_attr;
345
346 if (reply == NULL) {
347 fprintf(stderr, "Could not query value of %s: reply did not contain valid XML\n",
348 attr_name);
349 return -pcmk_err_schema_validation;
350 }
351 crm_log_xml_trace(reply, "Reply");
352
353 reply_attr = crm_element_value(reply, PCMK__XA_ATTR_NAME);
354 if (reply_attr == NULL) {
355 fprintf(stderr, "Could not query value of %s: attribute does not exist\n",
356 attr_name);
357 return -ENXIO;
358 }
359
360 if (!pcmk__str_eq(crm_element_value(reply, F_TYPE), T_ATTRD, pcmk__str_casei)
361 || (crm_element_value(reply, PCMK__XA_ATTR_VERSION) == NULL)
362 || strcmp(reply_attr, attr_name)) {
363 fprintf(stderr,
364 "Could not query value of %s: reply did not contain expected identification\n",
365 attr_name);
366 return -pcmk_err_schema_validation;
367 }
368 return pcmk_ok;
369 }
370
371
372
373
374
375
376
377
378
379 static gboolean
380 print_attrd_values(xmlNode *reply, const char *attr_name)
381 {
382 xmlNode *child;
383 const char *reply_host, *reply_value;
384 gboolean have_values = FALSE;
385
386
387 for (child = pcmk__xml_first_child(reply); child != NULL;
388 child = pcmk__xml_next(child)) {
389
390 if (!pcmk__str_eq((const char *)child->name, XML_CIB_TAG_NODE,
391 pcmk__str_casei)) {
392 crm_warn("Ignoring unexpected %s tag in query reply", child->name);
393 } else {
394 reply_host = crm_element_value(child, PCMK__XA_ATTR_NODE_NAME);
395 reply_value = crm_element_value(child, PCMK__XA_ATTR_VALUE);
396
397 if (reply_host == NULL) {
398 crm_warn("Ignoring %s tag without %s attribute in query reply",
399 XML_CIB_TAG_NODE, PCMK__XA_ATTR_NODE_NAME);
400 } else {
401 printf("name=\"%s\" host=\"%s\" value=\"%s\"\n",
402 attr_name, reply_host, (reply_value? reply_value : ""));
403 have_values = TRUE;
404 }
405 }
406 }
407 return have_values;
408 }
409
410
411
412
413
414
415
416
417
418
419 static int
420 do_query(const char *attr_name, const char *attr_node, gboolean query_all)
421 {
422 xmlNode *reply = NULL;
423 int rc;
424
425
426 if (query_all == TRUE) {
427 attr_node = NULL;
428 } else {
429 const char *target = pcmk__node_attr_target(attr_node);
430 if (target != NULL) {
431 attr_node = target;
432 }
433 }
434
435
436 rc = send_attrd_query(attr_name, attr_node, &reply);
437 if (rc != pcmk_ok) {
438 fprintf(stderr, "Could not query value of %s: %s (%d)\n", attr_name, pcmk_strerror(rc), rc);
439 return rc;
440 }
441
442
443 rc = validate_attrd_reply(reply, attr_name);
444 if (rc != pcmk_ok) {
445 if (reply != NULL) {
446 free_xml(reply);
447 }
448 return rc;
449 }
450
451
452 if (print_attrd_values(reply, attr_name) == FALSE) {
453 fprintf(stderr,
454 "Could not query value of %s: reply had attribute name but no host values\n",
455 attr_name);
456 free_xml(reply);
457 return -pcmk_err_schema_validation;
458 }
459
460 return pcmk_ok;
461 }
462
463 static int
464 do_update(char command, const char *attr_node, const char *attr_name,
465 const char *attr_value, const char *attr_section,
466 const char *attr_set, const char *attr_dampen, int attr_options)
467 {
468 int rc = pcmk__node_attr_request(NULL, command, attr_node, attr_name,
469 attr_value, attr_section, attr_set,
470 attr_dampen, NULL, attr_options);
471 if (rc != pcmk_rc_ok) {
472 fprintf(stderr, "Could not update %s=%s: %s (%d)\n",
473 attr_name, attr_value, pcmk_rc_str(rc), rc);
474 }
475 return rc;
476 }