This source file includes following definitions.
- build_query_reply
- attrd_client_clear_failure
- attrd_client_peer_remove
- attrd_client_query
- attrd_client_refresh
- handle_missing_host
- expand_regexes
- handle_regexes
- handle_value_expansion
- send_update_msg_to_cluster
- send_child_update
- attrd_client_update
- attrd_ipc_accept
- attrd_ipc_closed
- attrd_ipc_destroy
- attrd_ipc_dispatch
- attrd_ipc_fini
- attrd_init_ipc
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <errno.h>
13 #include <stdint.h>
14 #include <stdlib.h>
15 #include <sys/types.h>
16
17 #include <crm/cluster.h>
18 #include <crm/cluster/internal.h>
19 #include <crm/msg_xml.h>
20 #include <crm/common/acl_internal.h>
21 #include <crm/common/ipc_internal.h>
22 #include <crm/common/logging.h>
23 #include <crm/common/results.h>
24 #include <crm/common/strings_internal.h>
25 #include <crm/common/util.h>
26
27 #include "pacemaker-attrd.h"
28
29 static qb_ipcs_service_t *ipcs = NULL;
30
31
32
33
34
35
36
37
38
39
40
41 static xmlNode *build_query_reply(const char *attr, const char *host)
42 {
43 xmlNode *reply = create_xml_node(NULL, __func__);
44 attribute_t *a;
45
46 if (reply == NULL) {
47 return NULL;
48 }
49 crm_xml_add(reply, F_TYPE, T_ATTRD);
50 crm_xml_add(reply, F_SUBTYPE, PCMK__ATTRD_CMD_QUERY);
51 crm_xml_add(reply, PCMK__XA_ATTR_VERSION, ATTRD_PROTOCOL_VERSION);
52
53
54 a = g_hash_table_lookup(attributes, attr);
55 if (a) {
56 attribute_value_t *v;
57 xmlNode *host_value;
58
59 crm_xml_add(reply, PCMK__XA_ATTR_NAME, attr);
60
61
62 if (pcmk__str_eq(host, "localhost", pcmk__str_casei)) {
63 host = attrd_cluster->uname;
64 crm_trace("Mapped localhost to %s", host);
65 }
66
67
68 if (host) {
69 v = g_hash_table_lookup(a->values, host);
70 host_value = create_xml_node(reply, XML_CIB_TAG_NODE);
71 if (host_value == NULL) {
72 free_xml(reply);
73 return NULL;
74 }
75 pcmk__xe_add_node(host_value, host, 0);
76 crm_xml_add(host_value, PCMK__XA_ATTR_VALUE,
77 (v? v->current : NULL));
78
79
80 } else {
81 GHashTableIter iter;
82
83 g_hash_table_iter_init(&iter, a->values);
84 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &v)) {
85 host_value = create_xml_node(reply, XML_CIB_TAG_NODE);
86 if (host_value == NULL) {
87 free_xml(reply);
88 return NULL;
89 }
90 pcmk__xe_add_node(host_value, v->nodename, 0);
91 crm_xml_add(host_value, PCMK__XA_ATTR_VALUE, v->current);
92 }
93 }
94 }
95 return reply;
96 }
97
98 xmlNode *
99 attrd_client_clear_failure(pcmk__request_t *request)
100 {
101 xmlNode *xml = request->xml;
102 const char *rsc, *op, *interval_spec;
103
104 if (minimum_protocol_version >= 2) {
105
106
107
108 attrd_send_message(NULL, xml, false);
109 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
110 return NULL;
111 }
112
113 rsc = crm_element_value(xml, PCMK__XA_ATTR_RESOURCE);
114 op = crm_element_value(xml, PCMK__XA_ATTR_OPERATION);
115 interval_spec = crm_element_value(xml, PCMK__XA_ATTR_INTERVAL);
116
117
118 crm_xml_add(xml, PCMK__XA_TASK, PCMK__ATTRD_CMD_UPDATE);
119
120
121
122 if (rsc) {
123 char *pattern;
124
125 if (op == NULL) {
126 pattern = crm_strdup_printf(ATTRD_RE_CLEAR_ONE, rsc);
127
128 } else {
129 guint interval_ms = crm_parse_interval_spec(interval_spec);
130
131 pattern = crm_strdup_printf(ATTRD_RE_CLEAR_OP,
132 rsc, op, interval_ms);
133 }
134
135 crm_xml_add(xml, PCMK__XA_ATTR_PATTERN, pattern);
136 free(pattern);
137
138 } else {
139 crm_xml_add(xml, PCMK__XA_ATTR_PATTERN, ATTRD_RE_CLEAR_ALL);
140 }
141
142
143 xml_remove_prop(xml, PCMK__XA_ATTR_NAME);
144 xml_remove_prop(xml, PCMK__XA_ATTR_VALUE);
145
146 return attrd_client_update(request);
147 }
148
149 xmlNode *
150 attrd_client_peer_remove(pcmk__request_t *request)
151 {
152 xmlNode *xml = request->xml;
153
154
155 const char *host = crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME);
156 char *host_alloc = NULL;
157
158 attrd_send_ack(request->ipc_client, request->ipc_id, request->ipc_flags);
159
160 if (host == NULL) {
161 int nodeid = 0;
162
163 crm_element_value_int(xml, PCMK__XA_ATTR_NODE_ID, &nodeid);
164 if (nodeid > 0) {
165 crm_node_t *node = pcmk__search_cluster_node_cache(nodeid, NULL,
166 NULL);
167 char *host_alloc = NULL;
168
169 if (node && node->uname) {
170
171 host = node->uname;
172 } else {
173
174 host_alloc = get_node_name(nodeid);
175 host = host_alloc;
176 }
177 pcmk__xe_add_node(xml, host, 0);
178 }
179 }
180
181 if (host) {
182 crm_info("Client %s is requesting all values for %s be removed",
183 pcmk__client_name(request->ipc_client), host);
184 attrd_send_message(NULL, xml, false);
185 free(host_alloc);
186 } else {
187 crm_info("Ignoring request by client %s to remove all peer values without specifying peer",
188 pcmk__client_name(request->ipc_client));
189 }
190
191 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
192 return NULL;
193 }
194
195 xmlNode *
196 attrd_client_query(pcmk__request_t *request)
197 {
198 xmlNode *query = request->xml;
199 xmlNode *reply = NULL;
200 const char *attr = NULL;
201
202 crm_debug("Query arrived from %s", pcmk__client_name(request->ipc_client));
203
204
205 attr = crm_element_value(query, PCMK__XA_ATTR_NAME);
206 if (attr == NULL) {
207 pcmk__format_result(&request->result, CRM_EX_ERROR, PCMK_EXEC_ERROR,
208 "Ignoring malformed query from %s (no attribute name given)",
209 pcmk__client_name(request->ipc_client));
210 return NULL;
211 }
212
213
214 reply = build_query_reply(attr, crm_element_value(query,
215 PCMK__XA_ATTR_NODE_NAME));
216 if (reply == NULL) {
217 pcmk__format_result(&request->result, CRM_EX_ERROR, PCMK_EXEC_ERROR,
218 "Could not respond to query from %s: could not create XML reply",
219 pcmk__client_name(request->ipc_client));
220 return NULL;
221 } else {
222 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
223 }
224
225 request->ipc_client->request_id = 0;
226 return reply;
227 }
228
229 xmlNode *
230 attrd_client_refresh(pcmk__request_t *request)
231 {
232 crm_info("Updating all attributes");
233
234 attrd_send_ack(request->ipc_client, request->ipc_id, request->ipc_flags);
235 attrd_write_attributes(attrd_write_all|attrd_write_no_delay);
236
237 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
238 return NULL;
239 }
240
241 static void
242 handle_missing_host(xmlNode *xml)
243 {
244 const char *host = crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME);
245
246 if (host == NULL) {
247 crm_trace("Inferring host");
248 pcmk__xe_add_node(xml, attrd_cluster->uname, attrd_cluster->nodeid);
249 }
250 }
251
252
253
254
255 static int
256 expand_regexes(xmlNode *xml, const char *attr, const char *value, const char *regex)
257 {
258 if (attr == NULL && regex) {
259 bool matched = false;
260 GHashTableIter aIter;
261 regex_t r_patt;
262
263 crm_debug("Setting %s to %s", regex, value);
264 if (regcomp(&r_patt, regex, REG_EXTENDED|REG_NOSUB)) {
265 return EINVAL;
266 }
267
268 g_hash_table_iter_init(&aIter, attributes);
269 while (g_hash_table_iter_next(&aIter, (gpointer *) & attr, NULL)) {
270 int status = regexec(&r_patt, attr, 0, NULL, 0);
271
272 if (status == 0) {
273 xmlNode *child = create_xml_node(xml, XML_ATTR_OP);
274
275 crm_trace("Matched %s with %s", attr, regex);
276 matched = true;
277
278
279
280
281 attrd_copy_xml_attributes(xml, child);
282 xml_remove_prop(child, PCMK__XA_ATTR_PATTERN);
283 crm_xml_add(child, PCMK__XA_ATTR_NAME, attr);
284 }
285 }
286
287 regfree(&r_patt);
288
289
290
291
292
293
294 if (!matched) {
295 return pcmk_rc_op_unsatisfied;
296 }
297
298 } else if (attr == NULL) {
299 return pcmk_rc_bad_nvpair;
300 }
301
302 return pcmk_rc_ok;
303 }
304
305 static int
306 handle_regexes(pcmk__request_t *request)
307 {
308 xmlNode *xml = request->xml;
309 int rc = pcmk_rc_ok;
310
311 const char *attr = crm_element_value(xml, PCMK__XA_ATTR_NAME);
312 const char *value = crm_element_value(xml, PCMK__XA_ATTR_VALUE);
313 const char *regex = crm_element_value(xml, PCMK__XA_ATTR_PATTERN);
314
315 rc = expand_regexes(xml, attr, value, regex);
316
317 if (rc == EINVAL) {
318 pcmk__format_result(&request->result, CRM_EX_ERROR, PCMK_EXEC_ERROR,
319 "Bad regex '%s' for update from client %s", regex,
320 pcmk__client_name(request->ipc_client));
321
322 } else if (rc == pcmk_rc_bad_nvpair) {
323 crm_err("Update request did not specify attribute or regular expression");
324 pcmk__format_result(&request->result, CRM_EX_ERROR, PCMK_EXEC_ERROR,
325 "Client %s update request did not specify attribute or regular expression",
326 pcmk__client_name(request->ipc_client));
327 }
328
329 return rc;
330 }
331
332 static int
333 handle_value_expansion(const char **value, xmlNode *xml, const char *op,
334 const char *attr)
335 {
336 attribute_t *a = g_hash_table_lookup(attributes, attr);
337
338 if (a == NULL && pcmk__str_eq(op, PCMK__ATTRD_CMD_UPDATE_DELAY, pcmk__str_none)) {
339 return EINVAL;
340 }
341
342 if (*value && attrd_value_needs_expansion(*value)) {
343 int int_value;
344 attribute_value_t *v = NULL;
345
346 if (a) {
347 const char *host = crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME);
348 v = g_hash_table_lookup(a->values, host);
349 }
350
351 int_value = attrd_expand_value(*value, (v? v->current : NULL));
352
353 crm_info("Expanded %s=%s to %d", attr, *value, int_value);
354 crm_xml_add_int(xml, PCMK__XA_ATTR_VALUE, int_value);
355
356
357 *value = crm_element_value(xml, PCMK__XA_ATTR_VALUE);
358 }
359
360 return pcmk_rc_ok;
361 }
362
363 static void
364 send_update_msg_to_cluster(pcmk__request_t *request, xmlNode *xml)
365 {
366 if (pcmk__str_eq(attrd_request_sync_point(xml), PCMK__VALUE_CLUSTER, pcmk__str_none)) {
367
368
369
370
371 attrd_expect_confirmations(request, attrd_cluster_sync_point_update);
372 attrd_send_message(NULL, xml, true);
373
374 } else {
375
376
377
378
379
380
381 attrd_send_message(NULL, xml, false);
382 }
383 }
384
385 static int
386 send_child_update(xmlNode *child, void *data)
387 {
388 pcmk__request_t *request = (pcmk__request_t *) data;
389
390
391
392
393 request->xml = child;
394 attrd_client_update(request);
395 return pcmk_rc_ok;
396 }
397
398 xmlNode *
399 attrd_client_update(pcmk__request_t *request)
400 {
401 xmlNode *xml = NULL;
402 const char *attr, *value, *regex;
403
404 CRM_CHECK((request != NULL) && (request->xml != NULL), return NULL);
405
406 xml = request->xml;
407
408
409
410
411
412 if (xml->children != NULL) {
413 if (ATTRD_SUPPORTS_MULTI_MESSAGE(minimum_protocol_version)) {
414
415
416
417
418
419 for (xmlNode *child = first_named_child(xml, XML_ATTR_OP); child != NULL;
420 child = crm_next_same_xml(child)) {
421 attr = crm_element_value(child, PCMK__XA_ATTR_NAME);
422 value = crm_element_value(child, PCMK__XA_ATTR_VALUE);
423
424 handle_missing_host(child);
425
426 if (handle_value_expansion(&value, child, request->op, attr) == EINVAL) {
427 pcmk__format_result(&request->result, CRM_EX_NOSUCH, PCMK_EXEC_ERROR,
428 "Attribute %s does not exist", attr);
429 return NULL;
430 }
431 }
432
433 send_update_msg_to_cluster(request, xml);
434 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
435
436 } else {
437
438
439
440 xmlNode *orig_xml = request->xml;
441
442
443
444
445
446 pcmk__xe_foreach_child(xml, XML_ATTR_OP, send_child_update, request);
447 request->xml = orig_xml;
448 }
449
450 return NULL;
451 }
452
453 attr = crm_element_value(xml, PCMK__XA_ATTR_NAME);
454 value = crm_element_value(xml, PCMK__XA_ATTR_VALUE);
455 regex = crm_element_value(xml, PCMK__XA_ATTR_PATTERN);
456
457 if (handle_regexes(request) != pcmk_rc_ok) {
458
459 return NULL;
460 } else if (regex) {
461
462
463
464
465 return attrd_client_update(request);
466 }
467
468 handle_missing_host(xml);
469
470 if (handle_value_expansion(&value, xml, request->op, attr) == EINVAL) {
471 pcmk__format_result(&request->result, CRM_EX_NOSUCH, PCMK_EXEC_ERROR,
472 "Attribute %s does not exist", attr);
473 return NULL;
474 }
475
476 crm_debug("Broadcasting %s[%s]=%s%s", attr, crm_element_value(xml, PCMK__XA_ATTR_NODE_NAME),
477 value, (attrd_election_won()? " (writer)" : ""));
478
479 send_update_msg_to_cluster(request, xml);
480 pcmk__set_result(&request->result, CRM_EX_OK, PCMK_EXEC_DONE, NULL);
481 return NULL;
482 }
483
484
485
486
487
488
489
490
491
492
493
494 static int32_t
495 attrd_ipc_accept(qb_ipcs_connection_t *c, uid_t uid, gid_t gid)
496 {
497 crm_trace("New client connection %p", c);
498 if (attrd_shutting_down(false)) {
499 crm_info("Ignoring new connection from pid %d during shutdown",
500 pcmk__client_pid(c));
501 return -EPERM;
502 }
503
504 if (pcmk__new_client(c, uid, gid) == NULL) {
505 return -EIO;
506 }
507 return pcmk_ok;
508 }
509
510
511
512
513
514
515
516
517
518 static int32_t
519 attrd_ipc_closed(qb_ipcs_connection_t *c)
520 {
521 pcmk__client_t *client = pcmk__find_client(c);
522
523 if (client == NULL) {
524 crm_trace("Ignoring request to clean up unknown connection %p", c);
525 } else {
526 crm_trace("Cleaning up closed client connection %p", c);
527
528
529 attrd_remove_client_from_waitlist(client);
530
531
532 attrd_do_not_wait_for_client(client);
533
534 pcmk__free_client(client);
535 }
536
537 return FALSE;
538 }
539
540
541
542
543
544
545
546
547
548
549 static void
550 attrd_ipc_destroy(qb_ipcs_connection_t *c)
551 {
552 crm_trace("Destroying client connection %p", c);
553 attrd_ipc_closed(c);
554 }
555
556 static int32_t
557 attrd_ipc_dispatch(qb_ipcs_connection_t * c, void *data, size_t size)
558 {
559 uint32_t id = 0;
560 uint32_t flags = 0;
561 pcmk__client_t *client = pcmk__find_client(c);
562 xmlNode *xml = NULL;
563
564
565 CRM_CHECK((c != NULL) && (client != NULL), return 0);
566 if (data == NULL) {
567 crm_debug("No IPC data from PID %d", pcmk__client_pid(c));
568 return 0;
569 }
570
571 xml = pcmk__client_data2xml(client, data, &id, &flags);
572
573 if (xml == NULL) {
574 crm_debug("Unrecognizable IPC data from PID %d", pcmk__client_pid(c));
575 pcmk__ipc_send_ack(client, id, flags, "ack", NULL, CRM_EX_PROTOCOL);
576 return 0;
577
578 } else {
579 pcmk__request_t request = {
580 .ipc_client = client,
581 .ipc_id = id,
582 .ipc_flags = flags,
583 .peer = NULL,
584 .xml = xml,
585 .call_options = 0,
586 .result = PCMK__UNKNOWN_RESULT,
587 };
588
589 CRM_ASSERT(client->user != NULL);
590 pcmk__update_acl_user(xml, PCMK__XA_ATTR_USER, client->user);
591
592 request.op = crm_element_value_copy(request.xml, PCMK__XA_TASK);
593 CRM_CHECK(request.op != NULL, return 0);
594
595 attrd_handle_request(&request);
596 pcmk__reset_request(&request);
597 }
598
599 free_xml(xml);
600 return 0;
601 }
602
603 static struct qb_ipcs_service_handlers ipc_callbacks = {
604 .connection_accept = attrd_ipc_accept,
605 .connection_created = NULL,
606 .msg_process = attrd_ipc_dispatch,
607 .connection_closed = attrd_ipc_closed,
608 .connection_destroyed = attrd_ipc_destroy
609 };
610
611 void
612 attrd_ipc_fini(void)
613 {
614 if (ipcs != NULL) {
615 pcmk__drop_all_clients(ipcs);
616 qb_ipcs_destroy(ipcs);
617 ipcs = NULL;
618 }
619 }
620
621
622
623
624
625 void
626 attrd_init_ipc(void)
627 {
628 pcmk__serve_attrd_ipc(&ipcs, &ipc_callbacks);
629 }