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, 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, xmlNode *request)
173 {
174 int rc = pcmk_rc_ok;
175 int max = 5;
176
177 while (max > 0) {
178 crm_info("Connecting to cluster... %d retries remaining", max);
179 rc = pcmk_connect_ipc(api, pcmk_ipc_dispatch_sync);
180
181 if (rc == pcmk_rc_ok) {
182 rc = pcmk__send_ipc_request(api, request);
183 break;
184 } else if (rc == EAGAIN || rc == EALREADY) {
185 sleep(5 - max);
186 max--;
187 } else {
188 crm_err("Could not connect to attrd: %s", pcmk_rc_str(rc));
189 break;
190 }
191 }
192
193 return rc;
194 }
195
196 static int
197 send_attrd_request(pcmk_ipc_api_t *api, xmlNode *request)
198 {
199 return pcmk__send_ipc_request(api, request);
200 }
201
202 int
203 pcmk__attrd_api_clear_failures(pcmk_ipc_api_t *api, const char *node,
204 const char *resource, const char *operation,
205 const char *interval_spec, const char *user_name,
206 uint32_t options)
207 {
208 int rc = pcmk_rc_ok;
209 xmlNode *request = create_attrd_op(user_name);
210 const char *interval_desc = NULL;
211 const char *op_desc = NULL;
212 const char *target = pcmk__node_attr_target(node);
213
214 if (target != NULL) {
215 node = target;
216 }
217
218 crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_CLEAR_FAILURE);
219 pcmk__xe_add_node(request, node, 0);
220 crm_xml_add(request, PCMK__XA_ATTR_RESOURCE, resource);
221 crm_xml_add(request, PCMK__XA_ATTR_OPERATION, operation);
222 crm_xml_add(request, PCMK__XA_ATTR_INTERVAL, interval_spec);
223 crm_xml_add_int(request, PCMK__XA_ATTR_IS_REMOTE,
224 pcmk_is_set(options, pcmk__node_attr_remote));
225
226 if (api == NULL) {
227 rc = create_api(&api);
228 if (rc != pcmk_rc_ok) {
229 return rc;
230 }
231
232 rc = connect_and_send_attrd_request(api, request);
233 destroy_api(api);
234
235 } else if (!pcmk_ipc_is_connected(api)) {
236 rc = connect_and_send_attrd_request(api, request);
237
238 } else {
239 rc = send_attrd_request(api, request);
240 }
241
242 free_xml(request);
243
244 if (operation) {
245 interval_desc = interval_spec? interval_spec : "nonrecurring";
246 op_desc = operation;
247 } else {
248 interval_desc = "all";
249 op_desc = "operations";
250 }
251
252 crm_debug("Asked pacemaker-attrd to clear failure of %s %s for %s on %s: %s (%d)",
253 interval_desc, op_desc, (resource? resource : "all resources"),
254 (node? node : "all nodes"), pcmk_rc_str(rc), rc);
255
256 return rc;
257 }
258
259 int
260 pcmk__attrd_api_delete(pcmk_ipc_api_t *api, const char *node, const char *name,
261 uint32_t options)
262 {
263 const char *target = NULL;
264
265 if (name == NULL) {
266 return EINVAL;
267 }
268
269 target = pcmk__node_attr_target(node);
270
271 if (target != NULL) {
272 node = target;
273 }
274
275
276 options &= ~pcmk__node_attr_delay;
277 options |= pcmk__node_attr_value;
278
279 return pcmk__attrd_api_update(api, node, name, NULL, NULL, NULL, NULL, options);
280 }
281
282 int
283 pcmk__attrd_api_purge(pcmk_ipc_api_t *api, const char *node)
284 {
285 int rc = pcmk_rc_ok;
286 xmlNode *request = NULL;
287 const char *display_host = (node ? node : "localhost");
288 const char *target = pcmk__node_attr_target(node);
289
290 if (target != NULL) {
291 node = target;
292 }
293
294 request = create_attrd_op(NULL);
295
296 crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_PEER_REMOVE);
297 pcmk__xe_add_node(request, node, 0);
298
299 if (api == NULL) {
300 rc = create_api(&api);
301 if (rc != pcmk_rc_ok) {
302 return rc;
303 }
304
305 rc = connect_and_send_attrd_request(api, request);
306 destroy_api(api);
307
308 } else if (!pcmk_ipc_is_connected(api)) {
309 rc = connect_and_send_attrd_request(api, request);
310
311 } else {
312 rc = send_attrd_request(api, request);
313 }
314
315 free_xml(request);
316
317 crm_debug("Asked pacemaker-attrd to purge %s: %s (%d)",
318 display_host, pcmk_rc_str(rc), rc);
319
320 return rc;
321 }
322
323 int
324 pcmk__attrd_api_query(pcmk_ipc_api_t *api, const char *node, const char *name,
325 uint32_t options)
326 {
327 int rc = pcmk_rc_ok;
328 xmlNode *request = NULL;
329 const char *target = NULL;
330
331 if (name == NULL) {
332 return EINVAL;
333 }
334
335 target = pcmk__node_attr_target(node);
336
337 if (target != NULL) {
338 node = target;
339 }
340
341 request = create_attrd_op(NULL);
342
343 crm_xml_add(request, PCMK__XA_ATTR_NAME, name);
344 crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_QUERY);
345 pcmk__xe_add_node(request, node, 0);
346
347 rc = send_attrd_request(api, request);
348 free_xml(request);
349
350 if (node) {
351 crm_debug("Queried pacemaker-attrd for %s on %s: %s (%d)",
352 name, node, pcmk_rc_str(rc), rc);
353 } else {
354 crm_debug("Queried pacemaker-attrd for %s: %s (%d)",
355 name, pcmk_rc_str(rc), rc);
356 }
357
358 return rc;
359 }
360
361 int
362 pcmk__attrd_api_refresh(pcmk_ipc_api_t *api, const char *node)
363 {
364 int rc = pcmk_rc_ok;
365 xmlNode *request = NULL;
366 const char *display_host = (node ? node : "localhost");
367 const char *target = pcmk__node_attr_target(node);
368
369 if (target != NULL) {
370 node = target;
371 }
372
373 request = create_attrd_op(NULL);
374
375 crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_REFRESH);
376 pcmk__xe_add_node(request, node, 0);
377
378 if (api == NULL) {
379 rc = create_api(&api);
380 if (rc != pcmk_rc_ok) {
381 return rc;
382 }
383
384 rc = connect_and_send_attrd_request(api, request);
385 destroy_api(api);
386
387 } else if (!pcmk_ipc_is_connected(api)) {
388 rc = connect_and_send_attrd_request(api, request);
389
390 } else {
391 rc = send_attrd_request(api, request);
392 }
393
394 free_xml(request);
395
396 crm_debug("Asked pacemaker-attrd to refresh %s: %s (%d)",
397 display_host, pcmk_rc_str(rc), rc);
398
399 return rc;
400 }
401
402 static void
403 add_op_attr(xmlNode *op, uint32_t options)
404 {
405 if (pcmk_all_flags_set(options, pcmk__node_attr_value | pcmk__node_attr_delay)) {
406 crm_xml_add(op, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE_BOTH);
407 } else if (pcmk_is_set(options, pcmk__node_attr_value)) {
408 crm_xml_add(op, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE);
409 } else if (pcmk_is_set(options, pcmk__node_attr_delay)) {
410 crm_xml_add(op, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE_DELAY);
411 }
412 }
413
414 static void
415 populate_update_op(xmlNode *op, const char *node, const char *name, const char *value,
416 const char *dampen, const char *set, uint32_t options)
417 {
418 if (pcmk_is_set(options, pcmk__node_attr_pattern)) {
419 crm_xml_add(op, PCMK__XA_ATTR_PATTERN, name);
420 } else {
421 crm_xml_add(op, PCMK__XA_ATTR_NAME, name);
422 }
423
424 add_op_attr(op, options);
425
426 crm_xml_add(op, PCMK__XA_ATTR_VALUE, value);
427 crm_xml_add(op, PCMK__XA_ATTR_DAMPENING, dampen);
428 pcmk__xe_add_node(op, node, 0);
429 crm_xml_add(op, PCMK__XA_ATTR_SET, set);
430 crm_xml_add_int(op, PCMK__XA_ATTR_IS_REMOTE,
431 pcmk_is_set(options, pcmk__node_attr_remote));
432 crm_xml_add_int(op, PCMK__XA_ATTR_IS_PRIVATE,
433 pcmk_is_set(options, pcmk__node_attr_private));
434 }
435
436 int
437 pcmk__attrd_api_update(pcmk_ipc_api_t *api, const char *node, const char *name,
438 const char *value, const char *dampen, const char *set,
439 const char *user_name, uint32_t options)
440 {
441 int rc = pcmk_rc_ok;
442 xmlNode *request = NULL;
443 const char *display_host = (node ? node : "localhost");
444 const char *target = NULL;
445
446 if (name == NULL) {
447 return EINVAL;
448 }
449
450 target = pcmk__node_attr_target(node);
451
452 if (target != NULL) {
453 node = target;
454 }
455
456 request = create_attrd_op(user_name);
457 populate_update_op(request, node, name, value, dampen, set, options);
458
459 if (api == NULL) {
460 rc = create_api(&api);
461 if (rc != pcmk_rc_ok) {
462 return rc;
463 }
464
465 rc = connect_and_send_attrd_request(api, request);
466 destroy_api(api);
467
468 } else if (!pcmk_ipc_is_connected(api)) {
469 rc = connect_and_send_attrd_request(api, request);
470
471 } else {
472 rc = send_attrd_request(api, request);
473 }
474
475 free_xml(request);
476
477 crm_debug("Asked pacemaker-attrd to update %s on %s: %s (%d)",
478 name, display_host, pcmk_rc_str(rc), rc);
479
480 return rc;
481 }
482
483 int
484 pcmk__attrd_api_update_list(pcmk_ipc_api_t *api, GList *attrs, const char *dampen,
485 const char *set, const char *user_name,
486 uint32_t options)
487 {
488 int rc = pcmk_rc_ok;
489 xmlNode *request = NULL;
490
491 if (attrs == NULL) {
492 return EINVAL;
493 }
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517 for (GList *iter = attrs; iter != NULL; iter = iter->next) {
518 pcmk__attrd_query_pair_t *pair = (pcmk__attrd_query_pair_t *) iter->data;
519
520 if (pcmk__is_daemon) {
521 const char *target = NULL;
522 xmlNode *child = NULL;
523
524
525 if (request == NULL) {
526 request = create_attrd_op(user_name);
527 add_op_attr(request, options);
528 }
529
530
531
532
533
534
535 child = create_xml_node(request, XML_ATTR_OP);
536 target = pcmk__node_attr_target(pair->node);
537
538 if (target != NULL) {
539 pair->node = target;
540 }
541
542 populate_update_op(child, pair->node, pair->name, pair->value, dampen,
543 set, options);
544 } else {
545 rc = pcmk__attrd_api_update(api, pair->node, pair->name, pair->value,
546 dampen, set, user_name, options);
547 }
548 }
549
550
551
552
553 if (pcmk__is_daemon) {
554 bool created_api = false;
555
556 if (api == NULL) {
557 rc = create_api(&api);
558 if (rc != pcmk_rc_ok) {
559 return rc;
560 }
561
562 created_api = true;
563 }
564
565 rc = connect_and_send_attrd_request(api, request);
566 free_xml(request);
567
568 if (created_api) {
569 destroy_api(api);
570 }
571 }
572
573 return rc;
574 }