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
11
12
13
14
15
16
17
18
19
20 #include <crm_internal.h>
21
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <libgen.h>
26
27 #include <sys/param.h>
28 #include <sys/types.h>
29
30 #include <crm/crm.h>
31 #include <crm/msg_xml.h>
32 #include <crm/common/ipc.h>
33
34 #include <crm/attrd.h>
35
36
37 static struct crm_option long_options[] = {
38
39 {"help", 0, 0, '?', "\tThis text"},
40 {"version", 0, 0, '$', "\tVersion information" },
41 {"verbose", 0, 0, 'V', "\tIncrease debug output\n"},
42
43 {"name", 1, 0, 'n', "The attribute's name"},
44
45 {"-spacer-",1, 0, '-', "\nCommands:"},
46 {"update", 1, 0, 'U', "Update the attribute's value in attrd. If this causes the value to change, it will also be updated in the cluster configuration"},
47 {"update-both", 1, 0, 'B', "Update the attribute's value and time to wait (dampening) in attrd. If this causes the value or dampening to change, the attribute will also be written to the cluster configuration, so be aware that repeatedly changing the dampening reduces its effectiveness."},
48 #if HAVE_ATOMIC_ATTRD
49 {"update-delay", 0, 0, 'Y', "Update the attribute's dampening in attrd (requires -d/--delay). If this causes the dampening to change, the attribute will also be written to the cluster configuration, so be aware that repeatedly changing the dampening reduces its effectiveness."},
50 {"query", 0, 0, 'Q', "\tQuery the attribute's value from attrd"},
51 #endif
52 {"delete", 0, 0, 'D', "\tDelete the attribute in attrd. If a value was previously set, it will also be removed from the cluster configuration"},
53 {"refresh", 0, 0, 'R', "\t(Advanced) Force the attrd daemon to resend all current values to the CIB\n"},
54
55 {"-spacer-",1, 0, '-', "\nAdditional options:"},
56 {"delay", 1, 0, 'd', "The time to wait (dampening) in seconds for further changes before writing"},
57 {"set", 1, 0, 's', "(Advanced) The attribute set in which to place the value"},
58 {"node", 1, 0, 'N', "Set the attribute for the named node (instead of the local one)"},
59 #if HAVE_ATOMIC_ATTRD
60 {"all", 0, 0, 'A', "Show values of the attribute for all nodes (query only)"},
61
62 {"lifetime",1, 0, 'l', "(Deprecated) Lifetime of the node attribute (silently ignored by cluster)"},
63 {"private", 0, 0, 'p', "\tIf this creates a new attribute, never write the attribute to the CIB"},
64 #else
65 {"lifetime",1, 0, 'l', "Lifetime of the node attribute. Allowed values: forever, reboot"},
66 #endif
67
68
69 {"quiet", 0, 0, 'q', NULL, pcmk_option_hidden},
70 {"update", 1, 0, 'v', NULL, pcmk_option_hidden},
71 {"section", 1, 0, 'S', NULL, pcmk_option_hidden},
72 {0, 0, 0, 0}
73 };
74
75
76 #if HAVE_ATOMIC_ATTRD
77 static int do_query(const char *attr_name, const char *attr_node, gboolean query_all);
78 #endif
79 static int do_update(char command, const char *attr_node, const char *attr_name,
80 const char *attr_value, const char *attr_section,
81 const char *attr_set, const char *attr_dampen, int attr_options);
82
83 int
84 main(int argc, char **argv)
85 {
86 int index = 0;
87 int argerr = 0;
88 int attr_options = attrd_opt_none;
89 int flag;
90 const char *attr_node = NULL;
91 const char *attr_name = NULL;
92 const char *attr_value = NULL;
93 const char *attr_set = NULL;
94 const char *attr_section = NULL;
95 const char *attr_dampen = NULL;
96 char command = 'Q';
97
98 #if HAVE_ATOMIC_ATTRD
99 gboolean query_all = FALSE;
100 #endif
101
102 crm_log_cli_init("attrd_updater");
103 crm_set_options(NULL, "command -n attribute [options]", long_options,
104 "Tool for updating cluster node attributes");
105
106 if (argc < 2) {
107 crm_help('?', EX_USAGE);
108 }
109
110 while (1) {
111 flag = crm_get_option(argc, argv, &index);
112 if (flag == -1)
113 break;
114
115 switch (flag) {
116 case 'V':
117 crm_bump_log_level(argc, argv);
118 break;
119 case '?':
120 case '$':
121 crm_help(flag, EX_OK);
122 break;
123 case 'n':
124 attr_name = strdup(optarg);
125 break;
126 case 's':
127 attr_set = strdup(optarg);
128 break;
129 case 'd':
130 attr_dampen = strdup(optarg);
131 break;
132 case 'l':
133 case 'S':
134 attr_section = strdup(optarg);
135 break;
136 case 'N':
137 attr_node = strdup(optarg);
138 break;
139 #if HAVE_ATOMIC_ATTRD
140 case 'A':
141 query_all = TRUE;
142 break;
143 case 'p':
144 set_bit(attr_options, attrd_opt_private);
145 break;
146 #endif
147 case 'q':
148 break;
149 #if HAVE_ATOMIC_ATTRD
150 case 'Y':
151 command = flag;
152 crm_log_args(argc, argv);
153 break;
154 case 'Q':
155 #endif
156 case 'B':
157 case 'R':
158 case 'D':
159 case 'U':
160 case 'v':
161 command = flag;
162 attr_value = optarg;
163 crm_log_args(argc, argv);
164 break;
165 default:
166 ++argerr;
167 break;
168 }
169 }
170
171 if (optind > argc) {
172 ++argerr;
173 }
174
175 if (command != 'R' && attr_name == NULL) {
176 ++argerr;
177 }
178
179 if (argerr) {
180 crm_help('?', EX_USAGE);
181 }
182
183 if (command == 'Q') {
184 #if HAVE_ATOMIC_ATTRD
185 crm_exit(do_query(attr_name, attr_node, query_all));
186 #else
187 crm_help('?', EX_USAGE);
188 #endif
189 } else {
190
191
192
193
194
195
196
197
198
199
200
201
202
203 attr_node = attrd_get_target(attr_node);
204 crm_exit(do_update(command, attr_node, attr_name, attr_value,
205 attr_section, attr_set, attr_dampen, attr_options));
206 }
207 return crm_exit(pcmk_ok);
208 }
209
210 #if HAVE_ATOMIC_ATTRD
211
212
213
214
215
216
217
218
219
220
221
222
223 static int
224 send_attrd_query(const char *name, const char *host, xmlNode **reply)
225 {
226 int rc;
227 crm_ipc_t *ipc;
228 xmlNode *query;
229
230
231 query = create_xml_node(NULL, __FUNCTION__);
232 if (query == NULL) {
233 return -ENOMEM;
234 }
235 crm_xml_add(query, F_TYPE, T_ATTRD);
236 crm_xml_add(query, F_ORIG, crm_system_name);
237 crm_xml_add(query, F_ATTRD_HOST, host);
238 crm_xml_add(query, F_ATTRD_TASK, ATTRD_OP_QUERY);
239 crm_xml_add(query, F_ATTRD_ATTRIBUTE, name);
240
241
242 crm_debug("Sending query for value of %s on %s", name, (host? host : "all nodes"));
243 ipc = crm_ipc_new(T_ATTRD, 0);
244 if (crm_ipc_connect(ipc) == FALSE) {
245 crm_perror(LOG_ERR, "Connection to cluster attribute manager failed");
246 rc = -ENOTCONN;
247 } else {
248 rc = crm_ipc_send(ipc, query, crm_ipc_flags_none|crm_ipc_client_response, 0, reply);
249 if (rc > 0) {
250 rc = pcmk_ok;
251 }
252 crm_ipc_close(ipc);
253 }
254
255 free_xml(query);
256 return(rc);
257 }
258
259
260
261
262
263
264
265
266
267
268 static int
269 validate_attrd_reply(xmlNode *reply, const char *attr_name)
270 {
271 const char *reply_attr;
272
273 if (reply == NULL) {
274 fprintf(stderr, "Could not query value of %s: reply did not contain valid XML\n",
275 attr_name);
276 return -pcmk_err_schema_validation;
277 }
278 crm_log_xml_trace(reply, "Reply");
279
280 reply_attr = crm_element_value(reply, F_ATTRD_ATTRIBUTE);
281 if (reply_attr == NULL) {
282 fprintf(stderr, "Could not query value of %s: attribute does not exist\n",
283 attr_name);
284 return -ENXIO;
285 }
286
287 if (safe_str_neq(crm_element_value(reply, F_TYPE), T_ATTRD)
288 || (crm_element_value(reply, F_ATTRD_VERSION) == NULL)
289 || strcmp(reply_attr, attr_name)) {
290 fprintf(stderr,
291 "Could not query value of %s: reply did not contain expected identification\n",
292 attr_name);
293 return -pcmk_err_schema_validation;
294 }
295 return pcmk_ok;
296 }
297
298
299
300
301
302
303
304
305
306 static gboolean
307 print_attrd_values(xmlNode *reply, const char *attr_name)
308 {
309 xmlNode *child;
310 const char *reply_host, *reply_value;
311 gboolean have_values = FALSE;
312
313
314 for (child = __xml_first_child(reply); child != NULL; child = __xml_next(child)) {
315 if (safe_str_neq((const char*)child->name, XML_CIB_TAG_NODE)) {
316 crm_warn("Ignoring unexpected %s tag in query reply", child->name);
317 } else {
318 reply_host = crm_element_value(child, F_ATTRD_HOST);
319 reply_value = crm_element_value(child, F_ATTRD_VALUE);
320
321 if (reply_host == NULL) {
322 crm_warn("Ignoring %s tag without %s attribute in query reply",
323 XML_CIB_TAG_NODE, F_ATTRD_HOST);
324 } else {
325 printf("name=\"%s\" host=\"%s\" value=\"%s\"\n",
326 attr_name, reply_host, (reply_value? reply_value : ""));
327 have_values = TRUE;
328 }
329 }
330 }
331 return have_values;
332 }
333
334
335
336
337
338
339
340
341
342
343 static int
344 do_query(const char *attr_name, const char *attr_node, gboolean query_all)
345 {
346 xmlNode *reply = NULL;
347 int rc;
348
349
350 if (query_all == TRUE) {
351 attr_node = NULL;
352 } else {
353 attr_node = attrd_get_target(attr_node);
354 }
355
356
357 rc = send_attrd_query(attr_name, attr_node, &reply);
358 if (rc != pcmk_ok) {
359 fprintf(stderr, "Could not query value of %s: %s (%d)\n", attr_name, pcmk_strerror(rc), rc);
360 return rc;
361 }
362
363
364 rc = validate_attrd_reply(reply, attr_name);
365 if (rc != pcmk_ok) {
366 if (reply != NULL) {
367 free_xml(reply);
368 }
369 return rc;
370 }
371
372
373 if (print_attrd_values(reply, attr_name) == FALSE) {
374 fprintf(stderr,
375 "Could not query value of %s: reply had attribute name but no host values\n",
376 attr_name);
377 free_xml(reply);
378 return -pcmk_err_schema_validation;
379 }
380
381 return pcmk_ok;
382 }
383
384 #endif
385
386 static int
387 do_update(char command, const char *attr_node, const char *attr_name,
388 const char *attr_value, const char *attr_section,
389 const char *attr_set, const char *attr_dampen, int attr_options)
390 {
391 int rc = attrd_update_delegate(NULL, command, attr_node, attr_name,
392 attr_value, attr_section, attr_set,
393 attr_dampen, NULL, attr_options);
394 if (rc != pcmk_ok) {
395 fprintf(stderr, "Could not update %s=%s: %s (%d)\n", attr_name, attr_value, pcmk_strerror(rc), rc);
396 }
397 return rc;
398 }