This source file includes following definitions.
- set_pairs_data
- reply_expected
- dispatch
- pcmk__attrd_api_methods
- create_attrd_op
- create_api
- destroy_api
- connect_and_send_attrd_request
- send_attrd_request
- pcmk__attrd_api_clear_failures
- pcmk__attrd_api_delete
- pcmk__attrd_api_purge
- pcmk__attrd_api_query
- pcmk__attrd_api_refresh
- add_op_attr
- populate_update_op
- pcmk__attrd_api_update
- pcmk__attrd_api_update_list
1
2
3
4
5
6
7
8
9
10 #ifndef _GNU_SOURCE
11 # define _GNU_SOURCE
12 #endif
13
14 #include <crm_internal.h>
15
16 #include <stdio.h>
17
18 #include <crm/crm.h>
19 #include <crm/common/ipc.h>
20 #include <crm/common/ipc_attrd_internal.h>
21 #include <crm/common/attrd_internal.h>
22 #include <crm/msg_xml.h>
23 #include "crmcommon_private.h"
24
25 static void
26 set_pairs_data(pcmk__attrd_api_reply_t *data, xmlNode *msg_data)
27 {
28 const char *name = NULL;
29 pcmk__attrd_query_pair_t *pair;
30
31 name = crm_element_value(msg_data, PCMK__XA_ATTR_NAME);
32
33 for (xmlNode *node = first_named_child(msg_data, XML_CIB_TAG_NODE);
34 node != NULL; node = crm_next_same_xml(node)) {
35 pair = calloc(1, sizeof(pcmk__attrd_query_pair_t));
36
37 CRM_ASSERT(pair != NULL);
38
39 pair->node = crm_element_value(node, PCMK__XA_ATTR_NODE_NAME);
40 pair->name = name;
41 pair->value = crm_element_value(node, PCMK__XA_ATTR_VALUE);
42 data->data.pairs = g_list_prepend(data->data.pairs, pair);
43 }
44 }
45
46 static bool
47 reply_expected(pcmk_ipc_api_t *api, const xmlNode *request)
48 {
49 const char *command = crm_element_value(request, PCMK__XA_TASK);
50
51 return pcmk__str_any_of(command,
52 PCMK__ATTRD_CMD_CLEAR_FAILURE,
53 PCMK__ATTRD_CMD_QUERY,
54 PCMK__ATTRD_CMD_REFRESH,
55 PCMK__ATTRD_CMD_UPDATE,
56 PCMK__ATTRD_CMD_UPDATE_BOTH,
57 PCMK__ATTRD_CMD_UPDATE_DELAY,
58 NULL);
59 }
60
61 static bool
62 dispatch(pcmk_ipc_api_t *api, xmlNode *reply)
63 {
64 const char *value = NULL;
65 crm_exit_t status = CRM_EX_OK;
66
67 pcmk__attrd_api_reply_t reply_data = {
68 pcmk__attrd_reply_unknown
69 };
70
71 if (pcmk__str_eq((const char *) reply->name, "ack", pcmk__str_none)) {
72 return false;
73 }
74
75
76 value = crm_element_value(reply, F_TYPE);
77 if (pcmk__str_empty(value)
78 || !pcmk__str_eq(value, T_ATTRD, pcmk__str_none)) {
79 crm_info("Unrecognizable message from attribute manager: "
80 "message type '%s' not '" T_ATTRD "'", pcmk__s(value, ""));
81 status = CRM_EX_PROTOCOL;
82 goto done;
83 }
84
85 value = crm_element_value(reply, F_SUBTYPE);
86
87
88
89
90 if (pcmk__str_eq(value, PCMK__ATTRD_CMD_QUERY, pcmk__str_null_matches)) {
91 if (!xmlHasProp(reply, (pcmkXmlStr) PCMK__XA_ATTR_NAME)) {
92 status = ENXIO;
93 goto done;
94 }
95 reply_data.reply_type = pcmk__attrd_reply_query;
96 set_pairs_data(&reply_data, reply);
97
98 } else {
99 crm_info("Unrecognizable message from attribute manager: "
100 "message subtype '%s' unknown", pcmk__s(value, ""));
101 status = CRM_EX_PROTOCOL;
102 goto done;
103 }
104
105 done:
106 pcmk__call_ipc_callback(api, pcmk_ipc_event_reply, status, &reply_data);
107
108
109 if (reply_data.data.pairs) {
110 g_list_free_full(reply_data.data.pairs, free);
111 }
112
113 return false;
114 }
115
116 pcmk__ipc_methods_t *
117 pcmk__attrd_api_methods(void)
118 {
119 pcmk__ipc_methods_t *cmds = calloc(1, sizeof(pcmk__ipc_methods_t));
120
121 if (cmds != NULL) {
122 cmds->new_data = NULL;
123 cmds->free_data = NULL;
124 cmds->post_connect = NULL;
125 cmds->reply_expected = reply_expected;
126 cmds->dispatch = dispatch;
127 }
128 return cmds;
129 }
130
131
132
133
134
135
136
137
138
139 static xmlNode *
140 create_attrd_op(const char *user_name)
141 {
142 xmlNode *attrd_op = create_xml_node(NULL, __func__);
143
144 crm_xml_add(attrd_op, F_TYPE, T_ATTRD);
145 crm_xml_add(attrd_op, F_ORIG, (crm_system_name? crm_system_name: "unknown"));
146 crm_xml_add(attrd_op, PCMK__XA_ATTR_USER, user_name);
147
148 return attrd_op;
149 }
150
151 static int
152 create_api(pcmk_ipc_api_t **api)
153 {
154 int rc = pcmk_new_ipc_api(api, pcmk_ipc_attrd);
155
156 if (rc != pcmk_rc_ok) {
157 crm_err("Could not connect to attrd: %s", pcmk_rc_str(rc));
158 }
159
160 return rc;
161 }
162
163 static void
164 destroy_api(pcmk_ipc_api_t *api)
165 {
166 pcmk_disconnect_ipc(api);
167 pcmk_free_ipc_api(api);
168 api = NULL;
169 }
170
171 static int
172 connect_and_send_attrd_request(pcmk_ipc_api_t *api, const xmlNode *request)
173 {
174 int rc = pcmk_rc_ok;
175
176 rc = pcmk__connect_ipc(api, pcmk_ipc_dispatch_sync, 5);
177 if (rc != pcmk_rc_ok) {
178 crm_err("Could not connect to %s: %s",
179 pcmk_ipc_name(api, true), pcmk_rc_str(rc));
180 return rc;
181 }
182
183 rc = pcmk__send_ipc_request(api, request);
184 if (rc != pcmk_rc_ok) {
185 crm_err("Could not send request to %s: %s",
186 pcmk_ipc_name(api, true), pcmk_rc_str(rc));
187 return rc;
188 }
189
190 return pcmk_rc_ok;
191 }
192
193 static int
194 send_attrd_request(pcmk_ipc_api_t *api, const xmlNode *request)
195 {
196 return pcmk__send_ipc_request(api, request);
197 }
198
199 int
200 pcmk__attrd_api_clear_failures(pcmk_ipc_api_t *api, const char *node,
201 const char *resource, const char *operation,
202 const char *interval_spec, const char *user_name,
203 uint32_t options)
204 {
205 int rc = pcmk_rc_ok;
206 xmlNode *request = create_attrd_op(user_name);
207 const char *interval_desc = NULL;
208 const char *op_desc = NULL;
209 const char *target = pcmk__node_attr_target(node);
210
211 if (target != NULL) {
212 node = target;
213 }
214
215 crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_CLEAR_FAILURE);
216 pcmk__xe_add_node(request, node, 0);
217 crm_xml_add(request, PCMK__XA_ATTR_RESOURCE, resource);
218 crm_xml_add(request, PCMK__XA_ATTR_OPERATION, operation);
219 crm_xml_add(request, PCMK__XA_ATTR_INTERVAL, interval_spec);
220 crm_xml_add_int(request, PCMK__XA_ATTR_IS_REMOTE,
221 pcmk_is_set(options, pcmk__node_attr_remote));
222
223 if (api == NULL) {
224 rc = create_api(&api);
225 if (rc != pcmk_rc_ok) {
226 return rc;
227 }
228
229 rc = connect_and_send_attrd_request(api, request);
230 destroy_api(api);
231
232 } else if (!pcmk_ipc_is_connected(api)) {
233 rc = connect_and_send_attrd_request(api, request);
234
235 } else {
236 rc = send_attrd_request(api, request);
237 }
238
239 free_xml(request);
240
241 if (operation) {
242 interval_desc = interval_spec? interval_spec : "nonrecurring";
243 op_desc = operation;
244 } else {
245 interval_desc = "all";
246 op_desc = "operations";
247 }
248
249 crm_debug("Asked pacemaker-attrd to clear failure of %s %s for %s on %s: %s (%d)",
250 interval_desc, op_desc, (resource? resource : "all resources"),
251 (node? node : "all nodes"), pcmk_rc_str(rc), rc);
252
253 return rc;
254 }
255
256 int
257 pcmk__attrd_api_delete(pcmk_ipc_api_t *api, const char *node, const char *name,
258 uint32_t options)
259 {
260 const char *target = NULL;
261
262 if (name == NULL) {
263 return EINVAL;
264 }
265
266 target = pcmk__node_attr_target(node);
267
268 if (target != NULL) {
269 node = target;
270 }
271
272
273 options &= ~pcmk__node_attr_delay;
274 options |= pcmk__node_attr_value;
275
276 return pcmk__attrd_api_update(api, node, name, NULL, NULL, NULL, NULL, options);
277 }
278
279 int
280 pcmk__attrd_api_purge(pcmk_ipc_api_t *api, const char *node)
281 {
282 int rc = pcmk_rc_ok;
283 xmlNode *request = NULL;
284 const char *display_host = (node ? node : "localhost");
285 const char *target = pcmk__node_attr_target(node);
286
287 if (target != NULL) {
288 node = target;
289 }
290
291 request = create_attrd_op(NULL);
292
293 crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_PEER_REMOVE);
294 pcmk__xe_add_node(request, node, 0);
295
296 if (api == NULL) {
297 rc = create_api(&api);
298 if (rc != pcmk_rc_ok) {
299 return rc;
300 }
301
302 rc = connect_and_send_attrd_request(api, request);
303 destroy_api(api);
304
305 } else if (!pcmk_ipc_is_connected(api)) {
306 rc = connect_and_send_attrd_request(api, request);
307
308 } else {
309 rc = send_attrd_request(api, request);
310 }
311
312 free_xml(request);
313
314 crm_debug("Asked pacemaker-attrd to purge %s: %s (%d)",
315 display_host, pcmk_rc_str(rc), rc);
316
317 return rc;
318 }
319
320 int
321 pcmk__attrd_api_query(pcmk_ipc_api_t *api, const char *node, const char *name,
322 uint32_t options)
323 {
324 int rc = pcmk_rc_ok;
325 xmlNode *request = NULL;
326 const char *target = NULL;
327
328 if (name == NULL) {
329 return EINVAL;
330 }
331
332 if (pcmk_is_set(options, pcmk__node_attr_query_all)) {
333 node = NULL;
334 } else {
335 target = pcmk__node_attr_target(node);
336
337 if (target != NULL) {
338 node = target;
339 }
340 }
341
342 request = create_attrd_op(NULL);
343
344 crm_xml_add(request, PCMK__XA_ATTR_NAME, name);
345 crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_QUERY);
346 pcmk__xe_add_node(request, node, 0);
347
348 rc = send_attrd_request(api, request);
349 free_xml(request);
350
351 if (node) {
352 crm_debug("Queried pacemaker-attrd for %s on %s: %s (%d)",
353 name, node, pcmk_rc_str(rc), rc);
354 } else {
355 crm_debug("Queried pacemaker-attrd for %s: %s (%d)",
356 name, pcmk_rc_str(rc), rc);
357 }
358
359 return rc;
360 }
361
362 int
363 pcmk__attrd_api_refresh(pcmk_ipc_api_t *api, const char *node)
364 {
365 int rc = pcmk_rc_ok;
366 xmlNode *request = NULL;
367 const char *display_host = (node ? node : "localhost");
368 const char *target = pcmk__node_attr_target(node);
369
370 if (target != NULL) {
371 node = target;
372 }
373
374 request = create_attrd_op(NULL);
375
376 crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_REFRESH);
377 pcmk__xe_add_node(request, node, 0);
378
379 if (api == NULL) {
380 rc = create_api(&api);
381 if (rc != pcmk_rc_ok) {
382 return rc;
383 }
384
385 rc = connect_and_send_attrd_request(api, request);
386 destroy_api(api);
387
388 } else if (!pcmk_ipc_is_connected(api)) {
389 rc = connect_and_send_attrd_request(api, request);
390
391 } else {
392 rc = send_attrd_request(api, request);
393 }
394
395 free_xml(request);
396
397 crm_debug("Asked pacemaker-attrd to refresh %s: %s (%d)",
398 display_host, pcmk_rc_str(rc), rc);
399
400 return rc;
401 }
402
403 static void
404 add_op_attr(xmlNode *op, uint32_t options)
405 {
406 if (pcmk_all_flags_set(options, pcmk__node_attr_value | pcmk__node_attr_delay)) {
407 crm_xml_add(op, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE_BOTH);
408 } else if (pcmk_is_set(options, pcmk__node_attr_value)) {
409 crm_xml_add(op, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE);
410 } else if (pcmk_is_set(options, pcmk__node_attr_delay)) {
411 crm_xml_add(op, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE_DELAY);
412 }
413 }
414
415 static void
416 populate_update_op(xmlNode *op, const char *node, const char *name, const char *value,
417 const char *dampen, const char *set, uint32_t options)
418 {
419 if (pcmk_is_set(options, pcmk__node_attr_pattern)) {
420 crm_xml_add(op, PCMK__XA_ATTR_PATTERN, name);
421 } else {
422 crm_xml_add(op, PCMK__XA_ATTR_NAME, name);
423 }
424
425 if (pcmk_is_set(options, pcmk__node_attr_utilization)) {
426 crm_xml_add(op, PCMK__XA_ATTR_SET_TYPE, XML_TAG_UTILIZATION);
427 } else {
428 crm_xml_add(op, PCMK__XA_ATTR_SET_TYPE, XML_TAG_ATTR_SETS);
429 }
430
431 add_op_attr(op, options);
432
433 crm_xml_add(op, PCMK__XA_ATTR_VALUE, value);
434 crm_xml_add(op, PCMK__XA_ATTR_DAMPENING, dampen);
435 pcmk__xe_add_node(op, node, 0);
436 crm_xml_add(op, PCMK__XA_ATTR_SET, set);
437 crm_xml_add_int(op, PCMK__XA_ATTR_IS_REMOTE,
438 pcmk_is_set(options, pcmk__node_attr_remote));
439 crm_xml_add_int(op, PCMK__XA_ATTR_IS_PRIVATE,
440 pcmk_is_set(options, pcmk__node_attr_private));
441
442 if (pcmk_is_set(options, pcmk__node_attr_sync_local)) {
443 crm_xml_add(op, PCMK__XA_ATTR_SYNC_POINT, PCMK__VALUE_LOCAL);
444 } else if (pcmk_is_set(options, pcmk__node_attr_sync_cluster)) {
445 crm_xml_add(op, PCMK__XA_ATTR_SYNC_POINT, PCMK__VALUE_CLUSTER);
446 }
447 }
448
449 int
450 pcmk__attrd_api_update(pcmk_ipc_api_t *api, const char *node, const char *name,
451 const char *value, const char *dampen, const char *set,
452 const char *user_name, uint32_t options)
453 {
454 int rc = pcmk_rc_ok;
455 xmlNode *request = NULL;
456 const char *display_host = (node ? node : "localhost");
457 const char *target = NULL;
458
459 if (name == NULL) {
460 return EINVAL;
461 }
462
463 target = pcmk__node_attr_target(node);
464
465 if (target != NULL) {
466 node = target;
467 }
468
469 request = create_attrd_op(user_name);
470 populate_update_op(request, node, name, value, dampen, set, options);
471
472 if (api == NULL) {
473 rc = create_api(&api);
474 if (rc != pcmk_rc_ok) {
475 return rc;
476 }
477
478 rc = connect_and_send_attrd_request(api, request);
479 destroy_api(api);
480
481 } else if (!pcmk_ipc_is_connected(api)) {
482 rc = connect_and_send_attrd_request(api, request);
483
484 } else {
485 rc = send_attrd_request(api, request);
486 }
487
488 free_xml(request);
489
490 crm_debug("Asked pacemaker-attrd to update %s on %s: %s (%d)",
491 name, display_host, pcmk_rc_str(rc), rc);
492
493 return rc;
494 }
495
496 int
497 pcmk__attrd_api_update_list(pcmk_ipc_api_t *api, GList *attrs, const char *dampen,
498 const char *set, const char *user_name,
499 uint32_t options)
500 {
501 int rc = pcmk_rc_ok;
502 xmlNode *request = NULL;
503
504 if (attrs == NULL) {
505 return EINVAL;
506 }
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530 for (GList *iter = attrs; iter != NULL; iter = iter->next) {
531 pcmk__attrd_query_pair_t *pair = (pcmk__attrd_query_pair_t *) iter->data;
532
533 if (pcmk__is_daemon) {
534 const char *target = NULL;
535 xmlNode *child = NULL;
536
537
538 if (request == NULL) {
539 request = create_attrd_op(user_name);
540 add_op_attr(request, options);
541 }
542
543
544
545
546
547
548 child = create_xml_node(request, XML_ATTR_OP);
549 target = pcmk__node_attr_target(pair->node);
550
551 if (target != NULL) {
552 pair->node = target;
553 }
554
555 populate_update_op(child, pair->node, pair->name, pair->value, dampen,
556 set, options);
557 } else {
558 rc = pcmk__attrd_api_update(api, pair->node, pair->name, pair->value,
559 dampen, set, user_name, options);
560 }
561 }
562
563
564
565
566 if (pcmk__is_daemon) {
567 bool created_api = false;
568
569 if (api == NULL) {
570 rc = create_api(&api);
571 if (rc != pcmk_rc_ok) {
572 return rc;
573 }
574
575 created_api = true;
576 }
577
578 rc = connect_and_send_attrd_request(api, request);
579 free_xml(request);
580
581 if (created_api) {
582 destroy_api(api);
583 }
584 }
585
586 return rc;
587 }