root/cib/notify.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. need_pre_notify
  2. need_post_notify
  3. cib_notify_send_one
  4. cib_notify_send
  5. cib_pre_notify
  6. cib_post_notify
  7. cib_diff_notify
  8. do_cib_notify
  9. attach_cib_generation
  10. cib_replace_notify

   1 /*
   2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) any later version.
   8  *
   9  * This software is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU General Public
  15  * License along with this library; if not, write to the Free Software
  16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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     /* TODO: consider pre-notification for removal */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */