This source file includes following definitions.
- attribute_timer_cb
- attrd_cib_callback
- build_update_element
- send_alert_attributes_value
- set_alert_attribute_value
- attrd_add_timer
- attrd_write_attribute
- attrd_write_attributes
- attrd_write_or_elect_attribute
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <errno.h>
13 #include <stdbool.h>
14 #include <stdlib.h>
15 #include <glib.h>
16
17 #include <crm/msg_xml.h>
18 #include <crm/common/logging.h>
19 #include <crm/common/results.h>
20 #include <crm/common/strings_internal.h>
21 #include <crm/common/xml.h>
22
23 #include "pacemaker-attrd.h"
24
25 static int last_cib_op_done = 0;
26
27 static gboolean
28 attribute_timer_cb(gpointer data)
29 {
30 attribute_t *a = data;
31 crm_trace("Dampen interval expired for %s", a->id);
32 attrd_write_or_elect_attribute(a);
33 return FALSE;
34 }
35
36 static void
37 attrd_cib_callback(xmlNode *msg, int call_id, int rc, xmlNode *output, void *user_data)
38 {
39 int level = LOG_ERR;
40 GHashTableIter iter;
41 const char *peer = NULL;
42 attribute_value_t *v = NULL;
43
44 char *name = user_data;
45 attribute_t *a = g_hash_table_lookup(attributes, name);
46
47 if(a == NULL) {
48 crm_info("Attribute %s no longer exists", name);
49 return;
50 }
51
52 a->update = 0;
53 if (rc == pcmk_ok && call_id < 0) {
54 rc = call_id;
55 }
56
57 switch (rc) {
58 case pcmk_ok:
59 level = LOG_INFO;
60 last_cib_op_done = call_id;
61 if (a->timer && !a->timeout_ms) {
62
63 mainloop_timer_del(a->timer);
64 a->timer = NULL;
65 }
66 break;
67
68 case -pcmk_err_diff_failed:
69 case -ETIME:
70 case -ENXIO:
71
72
73 level = LOG_WARNING;
74 break;
75 }
76
77 do_crm_log(level, "CIB update %d result for %s: %s " CRM_XS " rc=%d",
78 call_id, a->id, pcmk_strerror(rc), rc);
79
80 g_hash_table_iter_init(&iter, a->values);
81 while (g_hash_table_iter_next(&iter, (gpointer *) & peer, (gpointer *) & v)) {
82 do_crm_log(level, "* %s[%s]=%s", a->id, peer, v->requested);
83 free(v->requested);
84 v->requested = NULL;
85 if (rc != pcmk_ok) {
86 a->changed = true;
87 }
88 }
89
90 if (a->changed && attrd_election_won()) {
91 if (rc == pcmk_ok) {
92
93
94
95 attrd_write_attribute(a, false);
96
97
98
99
100
101
102
103
104
105
106 } else if (a->timer) {
107
108 if (!mainloop_timer_running(a->timer)) {
109 crm_trace("Delayed re-attempted write for %s by %s",
110 name, pcmk__readable_interval(a->timeout_ms));
111 mainloop_timer_start(a->timer);
112 }
113 } else {
114
115
116
117
118 a->timer = attrd_add_timer(a->id, 2000, a);
119 mainloop_timer_start(a->timer);
120 }
121 }
122 }
123
124 static void
125 build_update_element(xmlNode *parent, attribute_t *a, const char *nodeid, const char *value)
126 {
127 const char *set = NULL;
128 xmlNode *xml_obj = NULL;
129
130 xml_obj = create_xml_node(parent, XML_CIB_TAG_STATE);
131 crm_xml_add(xml_obj, XML_ATTR_ID, nodeid);
132
133 xml_obj = create_xml_node(xml_obj, XML_TAG_TRANSIENT_NODEATTRS);
134 crm_xml_add(xml_obj, XML_ATTR_ID, nodeid);
135
136 if (pcmk__str_eq(a->set_type, XML_TAG_ATTR_SETS, pcmk__str_null_matches)) {
137 xml_obj = create_xml_node(xml_obj, XML_TAG_ATTR_SETS);
138 } else if (pcmk__str_eq(a->set_type, XML_TAG_UTILIZATION, pcmk__str_none)) {
139 xml_obj = create_xml_node(xml_obj, XML_TAG_UTILIZATION);
140 } else {
141 crm_err("Unknown set type attribute: %s", a->set_type);
142 }
143
144 if (a->set_id) {
145 crm_xml_set_id(xml_obj, "%s", a->set_id);
146 } else {
147 crm_xml_set_id(xml_obj, "%s-%s", XML_CIB_TAG_STATUS, nodeid);
148 }
149 set = ID(xml_obj);
150
151 xml_obj = create_xml_node(xml_obj, XML_CIB_TAG_NVPAIR);
152 if (a->uuid) {
153 crm_xml_set_id(xml_obj, "%s", a->uuid);
154 } else {
155 crm_xml_set_id(xml_obj, "%s-%s", set, a->id);
156 }
157 crm_xml_add(xml_obj, XML_NVPAIR_ATTR_NAME, a->id);
158
159 if(value) {
160 crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, value);
161
162 } else {
163 crm_xml_add(xml_obj, XML_NVPAIR_ATTR_VALUE, "");
164 crm_xml_add(xml_obj, "__delete__", XML_NVPAIR_ATTR_VALUE);
165 }
166 }
167
168 static void
169 send_alert_attributes_value(attribute_t *a, GHashTable *t)
170 {
171 int rc = 0;
172 attribute_value_t *at = NULL;
173 GHashTableIter vIter;
174
175 g_hash_table_iter_init(&vIter, t);
176
177 while (g_hash_table_iter_next(&vIter, NULL, (gpointer *) & at)) {
178 rc = attrd_send_attribute_alert(at->nodename, at->nodeid,
179 a->id, at->current);
180 crm_trace("Sent alerts for %s[%s]=%s: nodeid=%d rc=%d",
181 a->id, at->nodename, at->current, at->nodeid, rc);
182 }
183 }
184
185 static void
186 set_alert_attribute_value(GHashTable *t, attribute_value_t *v)
187 {
188 attribute_value_t *a_v = NULL;
189 a_v = calloc(1, sizeof(attribute_value_t));
190 CRM_ASSERT(a_v != NULL);
191
192 a_v->nodeid = v->nodeid;
193 a_v->nodename = strdup(v->nodename);
194 pcmk__str_update(&a_v->current, v->current);
195
196 g_hash_table_replace(t, a_v->nodename, a_v);
197 }
198
199 mainloop_timer_t *
200 attrd_add_timer(const char *id, int timeout_ms, attribute_t *attr)
201 {
202 return mainloop_timer_add(id, timeout_ms, FALSE, attribute_timer_cb, attr);
203 }
204
205 void
206 attrd_write_attribute(attribute_t *a, bool ignore_delay)
207 {
208 int private_updates = 0, cib_updates = 0;
209 xmlNode *xml_top = NULL;
210 attribute_value_t *v = NULL;
211 GHashTableIter iter;
212 enum cib_call_options flags = cib_none;
213 GHashTable *alert_attribute_value = NULL;
214
215 if (a == NULL) {
216 return;
217 }
218
219
220 if (!stand_alone && !a->is_private) {
221
222
223 CRM_CHECK(the_cib != NULL, return);
224 if (a->update && (a->update < last_cib_op_done)) {
225 crm_info("Write out of '%s' continuing: update %d considered lost", a->id, a->update);
226 a->update = 0;
227
228 } else if (a->update) {
229 crm_info("Write out of '%s' delayed: update %d in progress", a->id, a->update);
230 return;
231
232 } else if (mainloop_timer_running(a->timer)) {
233 if (ignore_delay) {
234
235
236
237 mainloop_timer_stop(a->timer);
238 crm_debug("Write out of '%s': timer is running but ignore delay", a->id);
239 } else {
240 crm_info("Write out of '%s' delayed: timer is running", a->id);
241 return;
242 }
243 }
244
245
246 xml_top = create_xml_node(NULL, XML_CIB_TAG_STATUS);
247 }
248
249
250 a->changed = false;
251
252
253 a->unknown_peer_uuids = false;
254
255
256 a->force_write = FALSE;
257
258
259 alert_attribute_value = pcmk__strikey_table(NULL, attrd_free_attribute_value);
260
261
262 g_hash_table_iter_init(&iter, a->values);
263 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & v)) {
264 crm_node_t *peer = crm_get_peer_full(v->nodeid, v->nodename, CRM_GET_PEER_ANY);
265
266
267 if (peer == NULL) {
268 crm_notice("Cannot update %s[%s]=%s because peer not known",
269 a->id, v->nodename, v->current);
270 continue;
271 }
272
273
274 if (peer->id && (v->nodeid == 0)) {
275 crm_trace("Learned ID %u for node %s", peer->id, v->nodename);
276 v->nodeid = peer->id;
277 }
278
279
280 if (stand_alone || a->is_private) {
281 private_updates++;
282 continue;
283 }
284
285
286 if (peer->uuid == NULL) {
287 a->unknown_peer_uuids = true;
288 crm_notice("Cannot update %s[%s]=%s because peer UUID not known "
289 "(will retry if learned)",
290 a->id, v->nodename, v->current);
291 continue;
292 }
293
294
295 crm_debug("Updating %s[%s]=%s (peer known as %s, UUID %s, ID %u/%u)",
296 a->id, v->nodename, v->current,
297 peer->uname, peer->uuid, peer->id, v->nodeid);
298 build_update_element(xml_top, a, peer->uuid, v->current);
299 cib_updates++;
300
301
302 set_alert_attribute_value(alert_attribute_value, v);
303
304 free(v->requested);
305 v->requested = NULL;
306 if (v->current) {
307 v->requested = strdup(v->current);
308 } else {
309
310
311
312 cib__set_call_options(flags, crm_system_name,
313 cib_mixed_update|cib_scope_local);
314 }
315 }
316
317 if (private_updates) {
318 crm_info("Processed %d private change%s for %s, id=%s, set=%s",
319 private_updates, pcmk__plural_s(private_updates),
320 a->id, pcmk__s(a->uuid, "n/a"), pcmk__s(a->set_id, "n/a"));
321 }
322 if (cib_updates) {
323 crm_log_xml_trace(xml_top, __func__);
324
325 a->update = cib_internal_op(the_cib, PCMK__CIB_REQUEST_MODIFY, NULL,
326 XML_CIB_TAG_STATUS, xml_top, NULL, flags,
327 a->user);
328
329 crm_info("Sent CIB request %d with %d change%s for %s (id %s, set %s)",
330 a->update, cib_updates, pcmk__plural_s(cib_updates),
331 a->id, pcmk__s(a->uuid, "n/a"), pcmk__s(a->set_id, "n/a"));
332
333 the_cib->cmds->register_callback_full(the_cib, a->update,
334 CIB_OP_TIMEOUT_S, FALSE,
335 strdup(a->id),
336 "attrd_cib_callback",
337 attrd_cib_callback, free);
338
339 send_alert_attributes_value(a, alert_attribute_value);
340 }
341
342 g_hash_table_destroy(alert_attribute_value);
343 free_xml(xml_top);
344 }
345
346 void
347 attrd_write_attributes(bool all, bool ignore_delay)
348 {
349 GHashTableIter iter;
350 attribute_t *a = NULL;
351
352 crm_debug("Writing out %s attributes", all? "all" : "changed");
353 g_hash_table_iter_init(&iter, attributes);
354 while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & a)) {
355 if (!all && a->unknown_peer_uuids) {
356
357 a->changed = true;
358 } else if (a->force_write) {
359
360 a->changed = true;
361 }
362
363 if(all || a->changed) {
364
365 attrd_write_attribute(a, (a->force_write ? true : ignore_delay));
366 } else {
367 crm_trace("Skipping unchanged attribute %s", a->id);
368 }
369 }
370 }
371
372 void
373 attrd_write_or_elect_attribute(attribute_t *a)
374 {
375 if (attrd_election_won()) {
376 attrd_write_attribute(a, false);
377 } else {
378 attrd_start_election_if_needed();
379 }
380 }