This source file includes following definitions.
- command_cb
- private_cb
- section_cb
- build_arg_context
- main
- print_attrd_values
- attrd_event_cb
- send_attrd_query
- send_attrd_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/ipc_attrd_internal.h>
23 #include <crm/common/cmdline_internal.h>
24 #include <crm/common/output_internal.h>
25 #include <crm/common/xml_internal.h>
26
27 #include <crm/common/attrd_internal.h>
28
29 #include <pcmki/pcmki_output.h>
30
31 #define SUMMARY "query and update Pacemaker node attributes"
32
33 static pcmk__supported_format_t formats[] = {
34 PCMK__SUPPORTED_FORMAT_NONE,
35 PCMK__SUPPORTED_FORMAT_TEXT,
36 PCMK__SUPPORTED_FORMAT_XML,
37 { NULL, NULL, NULL }
38 };
39
40 GError *error = NULL;
41 bool printed_values = false;
42
43 struct {
44 char command;
45 gchar *attr_dampen;
46 gchar *attr_name;
47 gchar *attr_node;
48 gchar *attr_set;
49 char *attr_value;
50 int attr_options;
51 gboolean query_all;
52 gboolean quiet;
53 } options = {
54 .attr_options = pcmk__node_attr_none,
55 .command = 'Q',
56 };
57
58 static gboolean
59 command_cb (const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
60 pcmk__str_update(&options.attr_value, optarg);
61
62 if (pcmk__str_any_of(option_name, "--update-both", "-B", NULL)) {
63 options.command = 'B';
64 } else if (pcmk__str_any_of(option_name, "--delete", "-D", NULL)) {
65 options.command = 'D';
66 } else if (pcmk__str_any_of(option_name, "--query", "-Q", NULL)) {
67 options.command = 'Q';
68 } else if (pcmk__str_any_of(option_name, "--refresh", "-R", NULL)) {
69 options.command = 'R';
70 } else if (pcmk__str_any_of(option_name, "--update", "-U", "-v", NULL)) {
71 options.command = 'U';
72 } else if (pcmk__str_any_of(option_name, "--update-delay", "-Y", NULL)) {
73 options.command = 'Y';
74 }
75
76 return TRUE;
77 }
78
79 static gboolean
80 private_cb (const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
81 pcmk__set_node_attr_flags(options.attr_options, pcmk__node_attr_private);
82 return TRUE;
83 }
84
85 static gboolean
86 section_cb (const gchar *option_name, const gchar *optarg, gpointer data, GError **err) {
87 if (pcmk__str_any_of(optarg, "nodes", "forever", NULL)) {
88 pcmk__set_node_attr_flags(options.attr_options, pcmk__node_attr_perm);
89 } else if (pcmk__str_any_of(optarg, "status", "reboot", NULL)) {
90 pcmk__clear_node_attr_flags(options.attr_options, pcmk__node_attr_perm);
91 } else {
92 g_set_error(err, PCMK__EXITC_ERROR, CRM_EX_USAGE, "Unknown value for --lifetime: %s",
93 optarg);
94 return FALSE;
95 }
96
97 return TRUE;
98 }
99
100 #define INDENT " "
101
102 static GOptionEntry required_entries[] = {
103 { "name", 'n', 0, G_OPTION_ARG_STRING, &options.attr_name,
104 "The attribute's name",
105 "NAME" },
106
107 { NULL }
108 };
109
110 static GOptionEntry command_entries[] = {
111 { "update", 'U', 0, G_OPTION_ARG_CALLBACK, command_cb,
112 "Update attribute's value in pacemaker-attrd. If this causes the value\n"
113 INDENT "to change, it will also be updated in the cluster configuration.",
114 "VALUE" },
115
116 { "update-both", 'B', 0, G_OPTION_ARG_CALLBACK, command_cb,
117 "Update attribute's value and time to wait (dampening) in\n"
118 INDENT "pacemaker-attrd. If this causes the value or dampening to change,\n"
119 INDENT "the attribute will also be written to the cluster configuration,\n"
120 INDENT "so be aware that repeatedly changing the dampening reduces its\n"
121 INDENT "effectiveness.\n"
122 INDENT "Requires -d/--delay",
123 "VALUE" },
124
125 { "update-delay", 'Y', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
126 "Update attribute's dampening in pacemaker-attrd. If this causes\n"
127 INDENT "the dampening to change, the attribute will also be written\n"
128 INDENT "to the cluster configuration, so be aware that repeatedly\n"
129 INDENT "changing the dampening reduces its effectiveness.\n"
130 INDENT "Requires -d/--delay",
131 NULL },
132
133 { "query", 'Q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
134 "Query the attribute's value from pacemaker-attrd",
135 NULL },
136
137 { "delete", 'D', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
138 "Unset attribute from pacemaker-attrd. At the moment, there is no way\n"
139 INDENT "to remove an attribute. This option will instead set its value\n"
140 INDENT "to the empty string.",
141 NULL },
142
143 { "refresh", 'R', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, command_cb,
144 "(Advanced) Force the pacemaker-attrd daemon to resend all current\n"
145 INDENT "values to the CIB",
146 NULL },
147
148 { NULL }
149 };
150
151 static GOptionEntry addl_entries[] = {
152 { "delay", 'd', 0, G_OPTION_ARG_STRING, &options.attr_dampen,
153 "The time to wait (dampening) in seconds for further changes\n"
154 INDENT "before sending to the CIB",
155 "SECONDS" },
156
157 { "set", 's', 0, G_OPTION_ARG_STRING, &options.attr_set,
158 "(Advanced) The attribute set in which to place the value",
159 "SET" },
160
161 { "node", 'N', 0, G_OPTION_ARG_STRING, &options.attr_node,
162 "Set the attribute for the named node (instead of the local one)",
163 "NODE" },
164
165 { "all", 'A', 0, G_OPTION_ARG_NONE, &options.query_all,
166 "Show values of the attribute for all nodes (query only)",
167 NULL },
168
169 { "lifetime", 'l', 0, G_OPTION_ARG_CALLBACK, section_cb,
170 "(Not yet implemented) Lifetime of the node attribute (silently\n"
171 INDENT "ignored by cluster)",
172 "SECTION" },
173
174 { "private", 'p', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, private_cb,
175 "If this creates a new attribute, never write the attribute to CIB",
176 NULL },
177
178 { NULL }
179 };
180
181 static GOptionEntry deprecated_entries[] = {
182 { "quiet", 'q', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &options.quiet,
183 NULL,
184 NULL },
185
186 { "update", 'v', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, command_cb,
187 NULL,
188 NULL },
189
190 { "section", 'S', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, section_cb,
191 NULL,
192 NULL },
193
194 { NULL }
195 };
196
197 static int send_attrd_query(pcmk__output_t *out, const char *attr_name, const char *attr_node,
198 gboolean query_all);
199 static int send_attrd_update(char command, const char *attr_node, const char *attr_name,
200 const char *attr_value, const char *attr_set,
201 const char *attr_dampen, uint32_t attr_options);
202
203 static GOptionContext *
204 build_arg_context(pcmk__common_args_t *args, GOptionGroup **group) {
205 GOptionContext *context = NULL;
206
207 context = pcmk__build_arg_context(args, "text (default), xml", group, NULL);
208
209 pcmk__add_arg_group(context, "required", "Required Arguments:",
210 "Show required arguments", required_entries);
211 pcmk__add_arg_group(context, "command", "Command:",
212 "Show command options (mutually exclusive)", command_entries);
213 pcmk__add_arg_group(context, "additional", "Additional Options:",
214 "Show additional options", addl_entries);
215 pcmk__add_arg_group(context, "deprecated", "Deprecated Options:",
216 "Show deprecated options", deprecated_entries);
217
218 return context;
219 }
220
221 int
222 main(int argc, char **argv)
223 {
224 int rc = pcmk_rc_ok;
225 crm_exit_t exit_code = CRM_EX_OK;
226
227 pcmk__output_t *out = NULL;
228
229 GOptionGroup *output_group = NULL;
230 pcmk__common_args_t *args = pcmk__new_common_args(SUMMARY);
231 GOptionContext *context = build_arg_context(args, &output_group);
232 gchar **processed_args = pcmk__cmdline_preproc(argv, "dlnsvBNUS");
233
234 pcmk__register_formats(output_group, formats);
235 if (!g_option_context_parse_strv(context, &processed_args, &error)) {
236 exit_code = CRM_EX_USAGE;
237 goto done;
238 }
239
240 pcmk__cli_init_logging("attrd_updater", args->verbosity);
241
242 rc = pcmk__output_new(&out, args->output_ty, args->output_dest, argv);
243 if (rc != pcmk_rc_ok) {
244 exit_code = CRM_EX_ERROR;
245 g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Error creating output format %s: %s",
246 args->output_ty, pcmk_rc_str(rc));
247 goto done;
248 }
249
250 if (args->version) {
251 out->version(out, false);
252 goto done;
253 }
254
255 if (options.command != 'R' && options.attr_name == NULL) {
256 exit_code = CRM_EX_USAGE;
257 g_set_error(&error, PCMK__EXITC_ERROR, exit_code, "Command requires --name argument");
258 goto done;
259 } else if ((options.command == 'B'|| options.command == 'Y') && options.attr_dampen == NULL) {
260 out->info(out, "Warning: '%c' command given without required --delay", options.command);
261 }
262
263 pcmk__register_lib_messages(out);
264
265 if (options.command == 'Q') {
266 int rc = send_attrd_query(out, options.attr_name, options.attr_node, options.query_all);
267 exit_code = pcmk_rc2exitc(rc);
268 } else {
269
270
271
272
273
274 int rc = send_attrd_update(options.command, options.attr_node,
275 options.attr_name, options.attr_value,
276 options.attr_set, options.attr_dampen,
277 options.attr_options);
278 exit_code = pcmk_rc2exitc(rc);
279 }
280
281 done:
282 g_strfreev(processed_args);
283 pcmk__free_arg_context(context);
284 g_free(options.attr_dampen);
285 g_free(options.attr_name);
286 g_free(options.attr_node);
287 g_free(options.attr_set);
288 free(options.attr_value);
289
290 pcmk__output_and_clear_error(error, out);
291
292 if (out != NULL) {
293 out->finish(out, exit_code, true, NULL);
294 pcmk__output_free(out);
295 }
296
297 crm_exit(exit_code);
298 }
299
300
301
302
303
304
305
306
307
308 static void
309 print_attrd_values(pcmk__output_t *out, GList *reply)
310 {
311 for (GList *iter = reply; iter != NULL; iter = iter->next) {
312 pcmk__attrd_query_pair_t *pair = (pcmk__attrd_query_pair_t *) iter->data;
313
314 out->message(out, "attribute", NULL, NULL, pair->name, pair->value,
315 pair->node);
316 printed_values = true;
317 }
318 }
319
320 static void
321 attrd_event_cb(pcmk_ipc_api_t *attrd_api, enum pcmk_ipc_event event_type,
322 crm_exit_t status, void *event_data, void *user_data)
323 {
324 pcmk__output_t *out = (pcmk__output_t *) user_data;
325 pcmk__attrd_api_reply_t *reply = event_data;
326
327 if (event_type != pcmk_ipc_event_reply || status != CRM_EX_OK) {
328 return;
329 }
330
331
332 if (reply->reply_type == pcmk__attrd_reply_query) {
333 print_attrd_values(out, reply->data.pairs);
334 }
335 }
336
337
338
339
340
341
342
343
344
345
346 static int
347 send_attrd_query(pcmk__output_t *out, const char *attr_name, const char *attr_node, gboolean query_all)
348 {
349 pcmk_ipc_api_t *attrd_api = NULL;
350 int rc = pcmk_rc_ok;
351
352
353 rc = pcmk_new_ipc_api(&attrd_api, pcmk_ipc_attrd);
354 if (rc != pcmk_rc_ok) {
355 g_set_error(&error, PCMK__RC_ERROR, rc,
356 "Could not connect to attrd: %s", pcmk_rc_str(rc));
357 return ENOTCONN;
358 }
359
360 pcmk_register_ipc_callback(attrd_api, attrd_event_cb, out);
361
362
363 rc = pcmk_connect_ipc(attrd_api, pcmk_ipc_dispatch_sync);
364 if (rc != pcmk_rc_ok) {
365 g_set_error(&error, PCMK__RC_ERROR, rc,
366 "Could not connect to attrd: %s", pcmk_rc_str(rc));
367 pcmk_free_ipc_api(attrd_api);
368 return rc;
369 }
370
371
372 if (query_all == TRUE) {
373 attr_node = NULL;
374 }
375
376 rc = pcmk__attrd_api_query(attrd_api, attr_node, attr_name, 0);
377
378 if (rc != pcmk_rc_ok) {
379 g_set_error(&error, PCMK__RC_ERROR, rc, "Could not query value of %s: %s (%d)",
380 attr_name, pcmk_strerror(rc), rc);
381 } else if (!printed_values) {
382 rc = pcmk_rc_schema_validation;
383 g_set_error(&error, PCMK__RC_ERROR, rc,
384 "Could not query value of %s: attribute does not exist", attr_name);
385 }
386
387 pcmk_disconnect_ipc(attrd_api);
388 pcmk_free_ipc_api(attrd_api);
389
390 return rc;
391 }
392
393 static int
394 send_attrd_update(char command, const char *attr_node, const char *attr_name,
395 const char *attr_value, const char *attr_set,
396 const char *attr_dampen, uint32_t attr_options)
397 {
398 int rc = pcmk_rc_ok;
399
400 switch (command) {
401 case 'B':
402 rc = pcmk__attrd_api_update(NULL, attr_node, attr_name, attr_value,
403 attr_dampen, attr_set, NULL,
404 attr_options | pcmk__node_attr_value | pcmk__node_attr_delay);
405 break;
406
407 case 'D':
408 rc = pcmk__attrd_api_delete(NULL, attr_node, attr_name, attr_options);
409 break;
410
411 case 'R':
412 rc = pcmk__attrd_api_refresh(NULL, attr_node);
413 break;
414
415 case 'U':
416 rc = pcmk__attrd_api_update(NULL, attr_node, attr_name, attr_value,
417 NULL, attr_set, NULL,
418 attr_options | pcmk__node_attr_value);
419 break;
420
421 case 'Y':
422 rc = pcmk__attrd_api_update(NULL, attr_node, attr_name, NULL,
423 attr_dampen, attr_set, NULL,
424 attr_options | pcmk__node_attr_delay);
425 break;
426 }
427
428 if (rc != pcmk_rc_ok) {
429 g_set_error(&error, PCMK__RC_ERROR, rc, "Could not update %s=%s: %s (%d)",
430 attr_name, attr_value, pcmk_rc_str(rc), rc);
431 }
432
433 return rc;
434 }