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 if (pcmk_is_set(options, pcmk__node_attr_query_all)) {
336 node = NULL;
337 } else {
338 target = pcmk__node_attr_target(node);
339
340 if (target != NULL) {
341 node = target;
342 }
343 }
344
345 request = create_attrd_op(NULL);
346
347 crm_xml_add(request, PCMK__XA_ATTR_NAME, name);
348 crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_QUERY);
349 pcmk__xe_add_node(request, node, 0);
350
351 rc = send_attrd_request(api, request);
352 free_xml(request);
353
354 if (node) {
355 crm_debug("Queried pacemaker-attrd for %s on %s: %s (%d)",
356 name, node, pcmk_rc_str(rc), rc);
357 } else {
358 crm_debug("Queried pacemaker-attrd for %s: %s (%d)",
359 name, pcmk_rc_str(rc), rc);
360 }
361
362 return rc;
363 }
364
365 int
366 pcmk__attrd_api_refresh(pcmk_ipc_api_t *api, const char *node)
367 {
368 int rc = pcmk_rc_ok;
369 xmlNode *request = NULL;
370 const char *display_host = (node ? node : "localhost");
371 const char *target = pcmk__node_attr_target(node);
372
373 if (target != NULL) {
374 node = target;
375 }
376
377 request = create_attrd_op(NULL);
378
379 crm_xml_add(request, PCMK__XA_TASK, PCMK__ATTRD_CMD_REFRESH);
380 pcmk__xe_add_node(request, node, 0);
381
382 if (api == NULL) {
383 rc = create_api(&api);
384 if (rc != pcmk_rc_ok) {
385 return rc;
386 }
387
388 rc = connect_and_send_attrd_request(api, request);
389 destroy_api(api);
390
391 } else if (!pcmk_ipc_is_connected(api)) {
392 rc = connect_and_send_attrd_request(api, request);
393
394 } else {
395 rc = send_attrd_request(api, request);
396 }
397
398 free_xml(request);
399
400 crm_debug("Asked pacemaker-attrd to refresh %s: %s (%d)",
401 display_host, pcmk_rc_str(rc), rc);
402
403 return rc;
404 }
405
406 static void
407 add_op_attr(xmlNode *op, uint32_t options)
408 {
409 if (pcmk_all_flags_set(options, pcmk__node_attr_value | pcmk__node_attr_delay)) {
410 crm_xml_add(op, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE_BOTH);
411 } else if (pcmk_is_set(options, pcmk__node_attr_value)) {
412 crm_xml_add(op, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE);
413 } else if (pcmk_is_set(options, pcmk__node_attr_delay)) {
414 crm_xml_add(op, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE_DELAY);
415 }
416 }
417
418 static void
419 populate_update_op(xmlNode *op, const char *node, const char *name, const char *value,
420 const char *dampen, const char *set, uint32_t options)
421 {
422 if (pcmk_is_set(options, pcmk__node_attr_pattern)) {
423 crm_xml_add(op, PCMK__XA_ATTR_PATTERN, name);
424 } else {
425 crm_xml_add(op, PCMK__XA_ATTR_NAME, name);
426 }
427
428 if (pcmk_is_set(options, pcmk__node_attr_utilization)) {
429 crm_xml_add(op, PCMK__XA_ATTR_SET_TYPE, XML_TAG_UTILIZATION);
430 } else {
431 crm_xml_add(op, PCMK__XA_ATTR_SET_TYPE, XML_TAG_ATTR_SETS);
432 }
433
434 add_op_attr(op, options);
435
436 crm_xml_add(op, PCMK__XA_ATTR_VALUE, value);
437 crm_xml_add(op, PCMK__XA_ATTR_DAMPENING, dampen);
438 pcmk__xe_add_node(op, node, 0);
439 crm_xml_add(op, PCMK__XA_ATTR_SET, set);
440 crm_xml_add_int(op, PCMK__XA_ATTR_IS_REMOTE,
441 pcmk_is_set(options, pcmk__node_attr_remote));
442 crm_xml_add_int(op, PCMK__XA_ATTR_IS_PRIVATE,
443 pcmk_is_set(options, pcmk__node_attr_private));
444
445 if (pcmk_is_set(options, pcmk__node_attr_sync_local)) {
446 crm_xml_add(op, PCMK__XA_ATTR_SYNC_POINT, PCMK__VALUE_LOCAL);
447 } else if (pcmk_is_set(options, pcmk__node_attr_sync_cluster)) {
448 crm_xml_add(op, PCMK__XA_ATTR_SYNC_POINT, PCMK__VALUE_CLUSTER);
449 }
450 }
451
452 int
453 pcmk__attrd_api_update(pcmk_ipc_api_t *api, const char *node, const char *name,
454 const char *value, const char *dampen, const char *set,
455 const char *user_name, uint32_t options)
456 {
457 int rc = pcmk_rc_ok;
458 xmlNode *request = NULL;
459 const char *display_host = (node ? node : "localhost");
460 const char *target = NULL;
461
462 if (name == NULL) {
463 return EINVAL;
464 }
465
466 target = pcmk__node_attr_target(node);
467
468 if (target != NULL) {
469 node = target;
470 }
471
472 request = create_attrd_op(user_name);
473 populate_update_op(request, node, name, value, dampen, set, options);
474
475 if (api == NULL) {
476 rc = create_api(&api);
477 if (rc != pcmk_rc_ok) {
478 return rc;
479 }
480
481 rc = connect_and_send_attrd_request(api, request);
482 destroy_api(api);
483
484 } else if (!pcmk_ipc_is_connected(api)) {
485 rc = connect_and_send_attrd_request(api, request);
486
487 } else {
488 rc = send_attrd_request(api, request);
489 }
490
491 free_xml(request);
492
493 crm_debug("Asked pacemaker-attrd to update %s on %s: %s (%d)",
494 name, display_host, pcmk_rc_str(rc), rc);
495
496 return rc;
497 }
498
499 int
500 pcmk__attrd_api_update_list(pcmk_ipc_api_t *api, GList *attrs, const char *dampen,
501 const char *set, const char *user_name,
502 uint32_t options)
503 {
504 int rc = pcmk_rc_ok;
505 xmlNode *request = NULL;
506
507 if (attrs == NULL) {
508 return EINVAL;
509 }
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533 for (GList *iter = attrs; iter != NULL; iter = iter->next) {
534 pcmk__attrd_query_pair_t *pair = (pcmk__attrd_query_pair_t *) iter->data;
535
536 if (pcmk__is_daemon) {
537 const char *target = NULL;
538 xmlNode *child = NULL;
539
540
541 if (request == NULL) {
542 request = create_attrd_op(user_name);
543 add_op_attr(request, options);
544 }
545
546
547
548
549
550
551 child = create_xml_node(request, XML_ATTR_OP);
552 target = pcmk__node_attr_target(pair->node);
553
554 if (target != NULL) {
555 pair->node = target;
556 }
557
558 populate_update_op(child, pair->node, pair->name, pair->value, dampen,
559 set, options);
560 } else {
561 rc = pcmk__attrd_api_update(api, pair->node, pair->name, pair->value,
562 dampen, set, user_name, options);
563 }
564 }
565
566
567
568
569 if (pcmk__is_daemon) {
570 bool created_api = false;
571
572 if (api == NULL) {
573 rc = create_api(&api);
574 if (rc != pcmk_rc_ok) {
575 return rc;
576 }
577
578 created_api = true;
579 }
580
581 rc = connect_and_send_attrd_request(api, request);
582 free_xml(request);
583
584 if (created_api) {
585 destroy_api(api);
586 }
587 }
588
589 return rc;
590 }