This source file includes following definitions.
- need_pre_notify
- need_post_notify
- cib_notify_send_one
- cib_notify_send
- cib_pre_notify
- cib_post_notify
- cib_diff_notify
- do_cib_notify
- attach_cib_generation
- cib_replace_notify
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <crm_internal.h>
20
21 #include <sys/param.h>
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <fcntl.h>
29
30 #include <time.h>
31
32 #include <crm/crm.h>
33 #include <crm/cib/internal.h>
34 #include <crm/msg_xml.h>
35
36 #include <crm/common/xml.h>
37 #include <cibio.h>
38 #include <callbacks.h>
39 #include <notify.h>
40
41 int pending_updates = 0;
42
43 struct cib_notification_s {
44 xmlNode *msg;
45 struct iovec *iov;
46 int32_t iov_size;
47 };
48
49 void attach_cib_generation(xmlNode * msg, const char *field, xmlNode * a_cib);
50
51 void do_cib_notify(int options, const char *op, xmlNode * update,
52 int result, xmlNode * result_data, const char *msg_type);
53
54 static void
55 need_pre_notify(gpointer key, gpointer value, gpointer user_data)
56 {
57 crm_client_t *client = value;
58
59 if (is_set(client->options, cib_notify_pre)) {
60 gboolean *needed = user_data;
61
62 *needed = TRUE;
63 }
64 }
65
66 static void
67 need_post_notify(gpointer key, gpointer value, gpointer user_data)
68 {
69 crm_client_t *client = value;
70
71 if (is_set(client->options, cib_notify_post)) {
72 gboolean *needed = user_data;
73
74 *needed = TRUE;
75 }
76 }
77
78 static gboolean
79 cib_notify_send_one(gpointer key, gpointer value, gpointer user_data)
80 {
81 const char *type = NULL;
82 gboolean do_send = FALSE;
83
84 crm_client_t *client = value;
85 struct cib_notification_s *update = user_data;
86
87 CRM_CHECK(client != NULL, return TRUE);
88 CRM_CHECK(update != NULL, return TRUE);
89
90 if (client->ipcs == NULL && client->remote == NULL) {
91 crm_warn("Skipping client with NULL channel");
92 return FALSE;
93 }
94
95 type = crm_element_value(update->msg, F_SUBTYPE);
96
97 CRM_LOG_ASSERT(type != NULL);
98 if (is_set(client->options, cib_notify_diff) && safe_str_eq(type, T_CIB_DIFF_NOTIFY)) {
99 do_send = TRUE;
100
101 } else if (is_set(client->options, cib_notify_replace)
102 && safe_str_eq(type, T_CIB_REPLACE_NOTIFY)) {
103 do_send = TRUE;
104
105 } else if (is_set(client->options, cib_notify_confirm)
106 && safe_str_eq(type, T_CIB_UPDATE_CONFIRM)) {
107 do_send = TRUE;
108
109 } else if (is_set(client->options, cib_notify_pre) && safe_str_eq(type, T_CIB_PRE_NOTIFY)) {
110 do_send = TRUE;
111
112 } else if (is_set(client->options, cib_notify_post) && safe_str_eq(type, T_CIB_POST_NOTIFY)) {
113 do_send = TRUE;
114 }
115
116 if (do_send) {
117 switch (client->kind) {
118 case CRM_CLIENT_IPC:
119 if (crm_ipcs_sendv(client, update->iov, crm_ipc_server_event) < 0) {
120 crm_warn("Notification of client %s/%s failed", client->name, client->id);
121 }
122 break;
123 #ifdef HAVE_GNUTLS_GNUTLS_H
124 case CRM_CLIENT_TLS:
125 #endif
126 case CRM_CLIENT_TCP:
127 crm_debug("Sent %s notification to client %s/%s", type, client->name, client->id);
128 crm_remote_send(client->remote, update->msg);
129 break;
130 default:
131 crm_err("Unknown transport %d for %s", client->kind, client->name);
132 }
133 }
134 return FALSE;
135 }
136
137 static void
138 cib_notify_send(xmlNode * xml)
139 {
140 struct iovec *iov;
141 struct cib_notification_s update;
142
143 ssize_t rc = crm_ipc_prepare(0, xml, &iov, 0);
144
145 crm_trace("Notifying clients");
146
147 if (rc > 0) {
148 update.msg = xml;
149 update.iov = iov;
150 update.iov_size = rc;
151 g_hash_table_foreach_remove(client_connections, cib_notify_send_one, &update);
152
153 } else {
154 crm_notice("Notification failed: %s (%d)", pcmk_strerror(rc), rc);
155 }
156
157 if (iov) {
158 free(iov[0].iov_base);
159 free(iov[1].iov_base);
160 free(iov);
161 }
162
163 crm_trace("Notify complete");
164 }
165
166 void
167 cib_pre_notify(int options, const char *op, xmlNode * existing, xmlNode * update)
168 {
169 xmlNode *update_msg = NULL;
170 const char *type = NULL;
171 const char *id = NULL;
172 gboolean needed = FALSE;
173
174 g_hash_table_foreach(client_connections, need_pre_notify, &needed);
175 if (needed == FALSE) {
176 return;
177 }
178
179
180 update_msg = create_xml_node(NULL, "pre-notify");
181
182 if (update != NULL) {
183 id = crm_element_value(update, XML_ATTR_ID);
184 }
185
186 crm_xml_add(update_msg, F_TYPE, T_CIB_NOTIFY);
187 crm_xml_add(update_msg, F_SUBTYPE, T_CIB_PRE_NOTIFY);
188 crm_xml_add(update_msg, F_CIB_OPERATION, op);
189
190 if (id != NULL) {
191 crm_xml_add(update_msg, F_CIB_OBJID, id);
192 }
193
194 if (update != NULL) {
195 crm_xml_add(update_msg, F_CIB_OBJTYPE, crm_element_name(update));
196 } else if (existing != NULL) {
197 crm_xml_add(update_msg, F_CIB_OBJTYPE, crm_element_name(existing));
198 }
199
200 type = crm_element_value(update_msg, F_CIB_OBJTYPE);
201 attach_cib_generation(update_msg, "cib_generation", the_cib);
202
203 if (existing != NULL) {
204 add_message_xml(update_msg, F_CIB_EXISTING, existing);
205 }
206 if (update != NULL) {
207 add_message_xml(update_msg, F_CIB_UPDATE, update);
208 }
209
210 cib_notify_send(update_msg);
211
212 if (update == NULL) {
213 crm_trace("Performing operation %s (on section=%s)", op, type);
214
215 } else {
216 crm_trace("Performing %s on <%s%s%s>", op, type, id ? " id=" : "", id ? id : "");
217 }
218
219 free_xml(update_msg);
220 }
221
222 void
223 cib_post_notify(int options, const char *op, xmlNode * update, int result, xmlNode * new_obj)
224 {
225 gboolean needed = FALSE;
226
227 g_hash_table_foreach(client_connections, need_post_notify, &needed);
228 if (needed == FALSE) {
229 return;
230 }
231
232 do_cib_notify(options, op, update, result, new_obj, T_CIB_UPDATE_CONFIRM);
233 }
234
235 void
236 cib_diff_notify(int options, const char *client, const char *call_id, const char *op,
237 xmlNode * update, int result, xmlNode * diff)
238 {
239 int add_updates = 0;
240 int add_epoch = 0;
241 int add_admin_epoch = 0;
242
243 int del_updates = 0;
244 int del_epoch = 0;
245 int del_admin_epoch = 0;
246
247 int log_level = LOG_DEBUG_2;
248
249 if (diff == NULL) {
250 return;
251 }
252
253 if (result != pcmk_ok) {
254 log_level = LOG_WARNING;
255 }
256
257 cib_diff_version_details(diff, &add_admin_epoch, &add_epoch, &add_updates,
258 &del_admin_epoch, &del_epoch, &del_updates);
259
260 if (add_updates != del_updates) {
261 do_crm_log(log_level,
262 "Update (client: %s%s%s): %d.%d.%d -> %d.%d.%d (%s)",
263 client, call_id ? ", call:" : "", call_id ? call_id : "",
264 del_admin_epoch, del_epoch, del_updates,
265 add_admin_epoch, add_epoch, add_updates, pcmk_strerror(result));
266
267 } else if (diff != NULL) {
268 do_crm_log(log_level,
269 "Local-only Change (client:%s%s%s): %d.%d.%d (%s)",
270 client, call_id ? ", call: " : "", call_id ? call_id : "",
271 add_admin_epoch, add_epoch, add_updates, pcmk_strerror(result));
272 }
273
274 do_cib_notify(options, op, update, result, diff, T_CIB_DIFF_NOTIFY);
275 }
276
277 void
278 do_cib_notify(int options, const char *op, xmlNode * update,
279 int result, xmlNode * result_data, const char *msg_type)
280 {
281 xmlNode *update_msg = NULL;
282 const char *id = NULL;
283
284 update_msg = create_xml_node(NULL, "notify");
285
286 if (result_data != NULL) {
287 id = crm_element_value(result_data, XML_ATTR_ID);
288 }
289
290 crm_xml_add(update_msg, F_TYPE, T_CIB_NOTIFY);
291 crm_xml_add(update_msg, F_SUBTYPE, msg_type);
292 crm_xml_add(update_msg, F_CIB_OPERATION, op);
293 crm_xml_add_int(update_msg, F_CIB_RC, result);
294
295 if (id != NULL) {
296 crm_xml_add(update_msg, F_CIB_OBJID, id);
297 }
298
299 if (update != NULL) {
300 crm_trace("Setting type to update->name: %s", crm_element_name(update));
301 crm_xml_add(update_msg, F_CIB_OBJTYPE, crm_element_name(update));
302
303 } else if (result_data != NULL) {
304 crm_trace("Setting type to new_obj->name: %s", crm_element_name(result_data));
305 crm_xml_add(update_msg, F_CIB_OBJTYPE, crm_element_name(result_data));
306
307 } else {
308 crm_trace("Not Setting type");
309 }
310
311 attach_cib_generation(update_msg, "cib_generation", the_cib);
312 if (update != NULL) {
313 add_message_xml(update_msg, F_CIB_UPDATE, update);
314 }
315 if (result_data != NULL) {
316 add_message_xml(update_msg, F_CIB_UPDATE_RESULT, result_data);
317 }
318
319 cib_notify_send(update_msg);
320 free_xml(update_msg);
321 }
322
323 void
324 attach_cib_generation(xmlNode * msg, const char *field, xmlNode * a_cib)
325 {
326 xmlNode *generation = create_xml_node(NULL, XML_CIB_TAG_GENERATION_TUPPLE);
327
328 if (a_cib != NULL) {
329 copy_in_properties(generation, a_cib);
330 }
331 add_message_xml(msg, field, generation);
332 free_xml(generation);
333 }
334
335 void
336 cib_replace_notify(const char *origin, xmlNode * update, int result, xmlNode * diff)
337 {
338 xmlNode *replace_msg = NULL;
339
340 int add_updates = 0;
341 int add_epoch = 0;
342 int add_admin_epoch = 0;
343
344 int del_updates = 0;
345 int del_epoch = 0;
346 int del_admin_epoch = 0;
347
348 if (diff == NULL) {
349 return;
350 }
351
352 cib_diff_version_details(diff, &add_admin_epoch, &add_epoch, &add_updates,
353 &del_admin_epoch, &del_epoch, &del_updates);
354
355 if (del_updates < 0) {
356 crm_log_xml_debug(diff, "Bad replace diff");
357 }
358
359 if (add_updates != del_updates) {
360 crm_info("Replaced: %d.%d.%d -> %d.%d.%d from %s",
361 del_admin_epoch, del_epoch, del_updates,
362 add_admin_epoch, add_epoch, add_updates, crm_str(origin));
363 } else if (diff != NULL) {
364 crm_info("Local-only Replace: %d.%d.%d from %s",
365 add_admin_epoch, add_epoch, add_updates, crm_str(origin));
366 }
367
368 replace_msg = create_xml_node(NULL, "notify-replace");
369 crm_xml_add(replace_msg, F_TYPE, T_CIB_NOTIFY);
370 crm_xml_add(replace_msg, F_SUBTYPE, T_CIB_REPLACE_NOTIFY);
371 crm_xml_add(replace_msg, F_CIB_OPERATION, CIB_OP_REPLACE);
372 crm_xml_add_int(replace_msg, F_CIB_RC, result);
373 attach_cib_generation(replace_msg, "cib-replace-generation", update);
374
375 crm_log_xml_trace(replace_msg, "CIB Replaced");
376
377 cib_notify_send(replace_msg);
378 free_xml(replace_msg);
379 }