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 crm_log_cli_init("attrd_updater");
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 exit_code = pcmk_rc2exitc(do_update(command,
272 pcmk__node_attr_target(attr_node),
273 attr_name, attr_value,
274 attr_section, attr_set,
275 attr_dampen, attr_options));
276 }
277
278 cleanup_memory();
279 crm_exit(exit_code);
280 }
281
282
283
284
285
286
287
288
289
290
291
292
293 static int
294 send_attrd_query(const char *name, const char *host, xmlNode **reply)
295 {
296 int rc;
297 crm_ipc_t *ipc;
298 xmlNode *query;
299
300
301 query = create_xml_node(NULL, __func__);
302 if (query == NULL) {
303 return -ENOMEM;
304 }
305 crm_xml_add(query, F_TYPE, T_ATTRD);
306 crm_xml_add(query, F_ORIG, crm_system_name);
307 crm_xml_add(query, PCMK__XA_ATTR_NODE_NAME, host);
308 crm_xml_add(query, PCMK__XA_TASK, PCMK__ATTRD_CMD_QUERY);
309 crm_xml_add(query, PCMK__XA_ATTR_NAME, name);
310
311
312 crm_debug("Sending query for value of %s on %s", name, (host? host : "all nodes"));
313 ipc = crm_ipc_new(T_ATTRD, 0);
314 if (crm_ipc_connect(ipc) == FALSE) {
315 crm_perror(LOG_ERR, "Connection to cluster attribute manager failed");
316 rc = -ENOTCONN;
317 } else {
318 rc = crm_ipc_send(ipc, query, crm_ipc_client_response, 0, reply);
319 if (rc > 0) {
320 rc = pcmk_ok;
321 }
322 crm_ipc_close(ipc);
323 }
324 crm_ipc_destroy(ipc);
325
326 free_xml(query);
327 return(rc);
328 }
329
330
331
332
333
334
335
336
337
338
339 static int
340 validate_attrd_reply(xmlNode *reply, const char *attr_name)
341 {
342 const char *reply_attr;
343
344 if (reply == NULL) {
345 fprintf(stderr, "Could not query value of %s: reply did not contain valid XML\n",
346 attr_name);
347 return -pcmk_err_schema_validation;
348 }
349 crm_log_xml_trace(reply, "Reply");
350
351 reply_attr = crm_element_value(reply, PCMK__XA_ATTR_NAME);
352 if (reply_attr == NULL) {
353 fprintf(stderr, "Could not query value of %s: attribute does not exist\n",
354 attr_name);
355 return -ENXIO;
356 }
357
358 if (!pcmk__str_eq(crm_element_value(reply, F_TYPE), T_ATTRD, pcmk__str_casei)
359 || (crm_element_value(reply, PCMK__XA_ATTR_VERSION) == NULL)
360 || strcmp(reply_attr, attr_name)) {
361 fprintf(stderr,
362 "Could not query value of %s: reply did not contain expected identification\n",
363 attr_name);
364 return -pcmk_err_schema_validation;
365 }
366 return pcmk_ok;
367 }
368
369
370
371
372
373
374
375
376
377 static gboolean
378 print_attrd_values(xmlNode *reply, const char *attr_name)
379 {
380 xmlNode *child;
381 const char *reply_host, *reply_value;
382 gboolean have_values = FALSE;
383
384
385 for (child = pcmk__xml_first_child(reply); child != NULL;
386 child = pcmk__xml_next(child)) {
387
388 if (!pcmk__str_eq((const char *)child->name, XML_CIB_TAG_NODE,
389 pcmk__str_casei)) {
390 crm_warn("Ignoring unexpected %s tag in query reply", child->name);
391 } else {
392 reply_host = crm_element_value(child, PCMK__XA_ATTR_NODE_NAME);
393 reply_value = crm_element_value(child, PCMK__XA_ATTR_VALUE);
394
395 if (reply_host == NULL) {
396 crm_warn("Ignoring %s tag without %s attribute in query reply",
397 XML_CIB_TAG_NODE, PCMK__XA_ATTR_NODE_NAME);
398 } else {
399 printf("name=\"%s\" host=\"%s\" value=\"%s\"\n",
400 attr_name, reply_host, (reply_value? reply_value : ""));
401 have_values = TRUE;
402 }
403 }
404 }
405 return have_values;
406 }
407
408
409
410
411
412
413
414
415
416
417 static int
418 do_query(const char *attr_name, const char *attr_node, gboolean query_all)
419 {
420 xmlNode *reply = NULL;
421 int rc;
422
423
424 if (query_all == TRUE) {
425 attr_node = NULL;
426 } else {
427 attr_node = pcmk__node_attr_target(attr_node);
428 }
429
430
431 rc = send_attrd_query(attr_name, attr_node, &reply);
432 if (rc != pcmk_ok) {
433 fprintf(stderr, "Could not query value of %s: %s (%d)\n", attr_name, pcmk_strerror(rc), rc);
434 return rc;
435 }
436
437
438 rc = validate_attrd_reply(reply, attr_name);
439 if (rc != pcmk_ok) {
440 if (reply != NULL) {
441 free_xml(reply);
442 }
443 return rc;
444 }
445
446
447 if (print_attrd_values(reply, attr_name) == FALSE) {
448 fprintf(stderr,
449 "Could not query value of %s: reply had attribute name but no host values\n",
450 attr_name);
451 free_xml(reply);
452 return -pcmk_err_schema_validation;
453 }
454
455 return pcmk_ok;
456 }
457
458 static int
459 do_update(char command, const char *attr_node, const char *attr_name,
460 const char *attr_value, const char *attr_section,
461 const char *attr_set, const char *attr_dampen, int attr_options)
462 {
463 int rc = pcmk__node_attr_request(NULL, command, attr_node, attr_name,
464 attr_value, attr_section, attr_set,
465 attr_dampen, NULL, attr_options);
466 if (rc != pcmk_rc_ok) {
467 fprintf(stderr, "Could not update %s=%s: %s (%d)\n",
468 attr_name, attr_value, pcmk_rc_str(rc), rc);
469 }
470 return rc;
471 }