root/daemons/based/based_notify.c

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

DEFINITIONS

This source file includes following definitions.
  1. cib_notify_send_one
  2. cib_notify_send
  3. attach_cib_generation
  4. cib_diff_notify
  5. cib_replace_notify

   1 /*
   2  * Copyright 2004-2023 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <sys/param.h>
  13 #include <stdio.h>
  14 #include <sys/types.h>
  15 #include <unistd.h>
  16 #include <inttypes.h>           // PRIx64
  17 
  18 #include <stdlib.h>
  19 #include <errno.h>
  20 #include <fcntl.h>
  21 
  22 #include <time.h>
  23 
  24 #include <crm/crm.h>
  25 #include <crm/cib/internal.h>
  26 #include <crm/msg_xml.h>
  27 
  28 #include <crm/common/xml.h>
  29 #include <crm/common/remote_internal.h>
  30 #include <pacemaker-based.h>
  31 
  32 struct cib_notification_s {
  33     xmlNode *msg;
  34     struct iovec *iov;
  35     int32_t iov_size;
  36 };
  37 
  38 static void
  39 cib_notify_send_one(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  40 {
  41     const char *type = NULL;
  42     gboolean do_send = FALSE;
  43     int rc = pcmk_rc_ok;
  44 
  45     pcmk__client_t *client = value;
  46     struct cib_notification_s *update = user_data;
  47 
  48     if (client->ipcs == NULL && client->remote == NULL) {
  49         crm_warn("Skipping client with NULL channel");
  50         return;
  51     }
  52 
  53     type = crm_element_value(update->msg, F_SUBTYPE);
  54     CRM_LOG_ASSERT(type != NULL);
  55 
  56     if (pcmk_is_set(client->flags, cib_notify_diff)
  57         && pcmk__str_eq(type, T_CIB_DIFF_NOTIFY, pcmk__str_casei)) {
  58 
  59         do_send = TRUE;
  60 
  61     } else if (pcmk_is_set(client->flags, cib_notify_replace)
  62                && pcmk__str_eq(type, T_CIB_REPLACE_NOTIFY, pcmk__str_casei)) {
  63         do_send = TRUE;
  64 
  65     } else if (pcmk_is_set(client->flags, cib_notify_confirm)
  66                && pcmk__str_eq(type, T_CIB_UPDATE_CONFIRM, pcmk__str_casei)) {
  67         do_send = TRUE;
  68 
  69     } else if (pcmk_is_set(client->flags, cib_notify_pre)
  70                && pcmk__str_eq(type, T_CIB_PRE_NOTIFY, pcmk__str_casei)) {
  71         do_send = TRUE;
  72 
  73     } else if (pcmk_is_set(client->flags, cib_notify_post)
  74                && pcmk__str_eq(type, T_CIB_POST_NOTIFY, pcmk__str_casei)) {
  75 
  76         do_send = TRUE;
  77     }
  78 
  79     if (do_send) {
  80         switch (PCMK__CLIENT_TYPE(client)) {
  81             case pcmk__client_ipc:
  82                 rc = pcmk__ipc_send_iov(client, update->iov,
  83                                         crm_ipc_server_event);
  84                 if (rc != pcmk_rc_ok) {
  85                     crm_warn("Could not notify client %s: %s " CRM_XS " id=%s",
  86                              pcmk__client_name(client), pcmk_rc_str(rc),
  87                              client->id);
  88                 }
  89                 break;
  90 #ifdef HAVE_GNUTLS_GNUTLS_H
  91             case pcmk__client_tls:
  92 #endif
  93             case pcmk__client_tcp:
  94                 crm_debug("Sent %s notification to client %s (id %s)",
  95                           type, pcmk__client_name(client), client->id);
  96                 pcmk__remote_send_xml(client->remote, update->msg);
  97                 break;
  98             default:
  99                 crm_err("Unknown transport for client %s "
 100                         CRM_XS " flags=%#016" PRIx64,
 101                         pcmk__client_name(client), client->flags);
 102         }
 103     }
 104 }
 105 
 106 static void
 107 cib_notify_send(xmlNode * xml)
     /* [previous][next][first][last][top][bottom][index][help] */
 108 {
 109     struct iovec *iov;
 110     struct cib_notification_s update;
 111 
 112     ssize_t bytes = 0;
 113     int rc = pcmk__ipc_prepare_iov(0, xml, 0, &iov, &bytes);
 114 
 115     if (rc == pcmk_rc_ok) {
 116         update.msg = xml;
 117         update.iov = iov;
 118         update.iov_size = bytes;
 119         pcmk__foreach_ipc_client(cib_notify_send_one, &update);
 120 
 121     } else {
 122         crm_notice("Could not notify clients: %s " CRM_XS " rc=%d",
 123                    pcmk_rc_str(rc), rc);
 124     }
 125     pcmk_free_ipc_event(iov);
 126 }
 127 
 128 static void
 129 attach_cib_generation(xmlNode *msg, const char *field, xmlNode *a_cib)
     /* [previous][next][first][last][top][bottom][index][help] */
 130 {
 131     xmlNode *generation = create_xml_node(NULL, XML_CIB_TAG_GENERATION_TUPPLE);
 132 
 133     if (a_cib != NULL) {
 134         copy_in_properties(generation, a_cib);
 135     }
 136     add_message_xml(msg, field, generation);
 137     free_xml(generation);
 138 }
 139 
 140 void
 141 cib_diff_notify(const char *op, int result, const char *call_id,
     /* [previous][next][first][last][top][bottom][index][help] */
 142                 const char *client_id, const char *client_name,
 143                 const char *origin, xmlNode *update, xmlNode *diff)
 144 {
 145     int add_updates = 0;
 146     int add_epoch = 0;
 147     int add_admin_epoch = 0;
 148 
 149     int del_updates = 0;
 150     int del_epoch = 0;
 151     int del_admin_epoch = 0;
 152 
 153     uint8_t log_level = LOG_TRACE;
 154 
 155     xmlNode *update_msg = NULL;
 156     const char *type = NULL;
 157 
 158     if (diff == NULL) {
 159         return;
 160     }
 161 
 162     if (result != pcmk_ok) {
 163         log_level = LOG_WARNING;
 164     }
 165 
 166     cib_diff_version_details(diff, &add_admin_epoch, &add_epoch, &add_updates,
 167                              &del_admin_epoch, &del_epoch, &del_updates);
 168 
 169     if ((add_admin_epoch != del_admin_epoch)
 170         || (add_epoch != del_epoch)
 171         || (add_updates != del_updates)) {
 172 
 173         do_crm_log(log_level,
 174                    "Updated CIB generation %d.%d.%d to %d.%d.%d from client "
 175                    "%s%s%s (%s) (%s)",
 176                    del_admin_epoch, del_epoch, del_updates,
 177                    add_admin_epoch, add_epoch, add_updates,
 178                    client_name,
 179                    ((call_id != NULL)? " call " : ""), pcmk__s(call_id, ""),
 180                    pcmk__s(origin, "unspecified peer"), pcmk_strerror(result));
 181 
 182     } else if ((add_admin_epoch != 0)
 183                || (add_epoch != 0)
 184                || (add_updates != 0)) {
 185 
 186         do_crm_log(log_level,
 187                    "Local-only change to CIB generation %d.%d.%d from client "
 188                    "%s%s%s (%s) (%s)",
 189                    add_admin_epoch, add_epoch, add_updates,
 190                    client_name,
 191                    ((call_id != NULL)? " call " : ""), pcmk__s(call_id, ""),
 192                    pcmk__s(origin, "unspecified peer"), pcmk_strerror(result));
 193     }
 194 
 195     update_msg = create_xml_node(NULL, "notify");
 196 
 197     crm_xml_add(update_msg, F_TYPE, T_CIB_NOTIFY);
 198     crm_xml_add(update_msg, F_SUBTYPE, T_CIB_DIFF_NOTIFY);
 199     crm_xml_add(update_msg, F_CIB_OPERATION, op);
 200     crm_xml_add(update_msg, F_CIB_CLIENTID, client_id);
 201     crm_xml_add(update_msg, F_CIB_CALLID, call_id);
 202     crm_xml_add(update_msg, F_ORIG, origin);
 203     crm_xml_add_int(update_msg, F_CIB_RC, result);
 204 
 205     if (update != NULL) {
 206         type = crm_element_name(update);
 207         crm_trace("Setting type to update->name: %s", type);
 208     } else {
 209         type = crm_element_name(diff);
 210         crm_trace("Setting type to new_obj->name: %s", type);
 211     }
 212     crm_xml_add(update_msg, F_CIB_OBJID, ID(diff));
 213     crm_xml_add(update_msg, F_CIB_OBJTYPE, type);
 214     attach_cib_generation(update_msg, "cib_generation", the_cib);
 215 
 216     if (update != NULL) {
 217         add_message_xml(update_msg, F_CIB_UPDATE, update);
 218     }
 219     add_message_xml(update_msg, F_CIB_UPDATE_RESULT, diff);
 220 
 221     cib_notify_send(update_msg);
 222     free_xml(update_msg);
 223 }
 224 
 225 void
 226 cib_replace_notify(const char *op, int result, const char *call_id,
     /* [previous][next][first][last][top][bottom][index][help] */
 227                    const char *client_id, const char *client_name,
 228                    const char *origin, xmlNode *update, xmlNode *diff,
 229                    uint32_t change_section)
 230 {
 231     xmlNode *replace_msg = NULL;
 232 
 233     int add_updates = 0;
 234     int add_epoch = 0;
 235     int add_admin_epoch = 0;
 236 
 237     int del_updates = 0;
 238     int del_epoch = 0;
 239     int del_admin_epoch = 0;
 240 
 241     uint8_t log_level = LOG_INFO;
 242 
 243     if (diff == NULL) {
 244         return;
 245     }
 246 
 247     if (result != pcmk_ok) {
 248         log_level = LOG_WARNING;
 249     }
 250 
 251     cib_diff_version_details(diff, &add_admin_epoch, &add_epoch, &add_updates,
 252                              &del_admin_epoch, &del_epoch, &del_updates);
 253 
 254     if (del_updates < 0) {
 255         crm_log_xml_debug(diff, "Bad replace diff");
 256     }
 257 
 258     if ((add_admin_epoch != del_admin_epoch)
 259         || (add_epoch != del_epoch)
 260         || (add_updates != del_updates)) {
 261 
 262         do_crm_log(log_level,
 263                    "Replaced CIB generation %d.%d.%d with %d.%d.%d from client "
 264                    "%s%s%s (%s) (%s)",
 265                    del_admin_epoch, del_epoch, del_updates,
 266                    add_admin_epoch, add_epoch, add_updates,
 267                    client_name,
 268                    ((call_id != NULL)? " call " : ""), pcmk__s(call_id, ""),
 269                    pcmk__s(origin, "unspecified peer"), pcmk_strerror(result));
 270 
 271     } else if ((add_admin_epoch != 0)
 272                || (add_epoch != 0)
 273                || (add_updates != 0)) {
 274 
 275         do_crm_log(log_level,
 276                    "Local-only replace of CIB generation %d.%d.%d from client "
 277                    "%s%s%s (%s) (%s)",
 278                    add_admin_epoch, add_epoch, add_updates,
 279                    client_name,
 280                    ((call_id != NULL)? " call " : ""), pcmk__s(call_id, ""),
 281                    pcmk__s(origin, "unspecified peer"), pcmk_strerror(result));
 282     }
 283 
 284     replace_msg = create_xml_node(NULL, "notify-replace");
 285 
 286     crm_xml_add(replace_msg, F_TYPE, T_CIB_NOTIFY);
 287     crm_xml_add(replace_msg, F_SUBTYPE, T_CIB_REPLACE_NOTIFY);
 288     crm_xml_add(replace_msg, F_CIB_OPERATION, op);
 289     crm_xml_add(replace_msg, F_CIB_CLIENTID, client_id);
 290     crm_xml_add(replace_msg, F_CIB_CALLID, call_id);
 291     crm_xml_add(replace_msg, F_ORIG, origin);
 292     crm_xml_add_int(replace_msg, F_CIB_RC, result);
 293     crm_xml_add_ll(replace_msg, F_CIB_CHANGE_SECTION,
 294                    (long long) change_section);
 295     attach_cib_generation(replace_msg, "cib-replace-generation", update);
 296 
 297     /* We can include update and diff if a replace callback needs them. Until
 298      * then, avoid the overhead.
 299      */
 300 
 301     crm_log_xml_trace(replace_msg, "CIB replaced");
 302 
 303     cib_notify_send(replace_msg);
 304     free_xml(replace_msg);
 305 }

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