root/lib/pacemaker/pcmk_sched_notif.c

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

DEFINITIONS

This source file includes following definitions.
  1. sort_notify_entries
  2. dup_notify_entry
  3. expand_node_list
  4. expand_list
  5. dup_attr
  6. add_notify_data_to_action_meta
  7. pe_notify
  8. pe_post_notify
  9. create_notification_boundaries
  10. collect_notification_data
  11. pcmk__create_notification_keys
  12. find_remote_start
  13. create_notifications
  14. free_notification_data
  15. create_secondary_notification

   1 /*
   2  * Copyright 2004-2020 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 #include <crm/msg_xml.h>
  12 #include <pacemaker-internal.h>
  13 
  14 typedef struct notify_entry_s {
  15     pe_resource_t *rsc;
  16     pe_node_t *node;
  17 } notify_entry_t;
  18 
  19 static gint
  20 sort_notify_entries(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
  21 {
  22     int tmp;
  23     const notify_entry_t *entry_a = a;
  24     const notify_entry_t *entry_b = b;
  25 
  26     if (entry_a == NULL && entry_b == NULL) {
  27         return 0;
  28     }
  29     if (entry_a == NULL) {
  30         return 1;
  31     }
  32     if (entry_b == NULL) {
  33         return -1;
  34     }
  35 
  36     if (entry_a->rsc == NULL && entry_b->rsc == NULL) {
  37         return 0;
  38     }
  39     if (entry_a->rsc == NULL) {
  40         return 1;
  41     }
  42     if (entry_b->rsc == NULL) {
  43         return -1;
  44     }
  45 
  46     tmp = strcmp(entry_a->rsc->id, entry_b->rsc->id);
  47     if (tmp != 0) {
  48         return tmp;
  49     }
  50 
  51     if (entry_a->node == NULL && entry_b->node == NULL) {
  52         return 0;
  53     }
  54     if (entry_a->node == NULL) {
  55         return 1;
  56     }
  57     if (entry_b->node == NULL) {
  58         return -1;
  59     }
  60 
  61     return strcmp(entry_a->node->details->id, entry_b->node->details->id);
  62 }
  63 
  64 static notify_entry_t *dup_notify_entry(notify_entry_t *entry)
     /* [previous][next][first][last][top][bottom][index][help] */
  65 {
  66     notify_entry_t *dup = malloc(sizeof(notify_entry_t));
  67 
  68     CRM_ASSERT(dup != NULL);
  69     dup->rsc = entry->rsc;
  70     dup->node = entry->node;
  71     return dup;
  72 }
  73 
  74 static void
  75 expand_node_list(GListPtr list, char **uname, char **metal)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77     GListPtr gIter = NULL;
  78     char *node_list = NULL;
  79     char *metal_list = NULL;
  80     size_t node_list_len = 0;
  81     size_t metal_list_len = 0;
  82 
  83     CRM_ASSERT(uname != NULL);
  84     if (list == NULL) {
  85         *uname = strdup(" ");
  86         if(metal) {
  87             *metal = strdup(" ");
  88         }
  89         return;
  90     }
  91 
  92     for (gIter = list; gIter != NULL; gIter = gIter->next) {
  93         pe_node_t *node = (pe_node_t *) gIter->data;
  94 
  95         if (node->details->uname == NULL) {
  96             continue;
  97         }
  98         pcmk__add_word(&node_list, &node_list_len, node->details->uname);
  99         if(metal) {
 100             if(node->details->remote_rsc
 101                && node->details->remote_rsc->container
 102                && node->details->remote_rsc->container->running_on) {
 103                 node = pe__current_node(node->details->remote_rsc->container);
 104             }
 105 
 106             if (node->details->uname == NULL) {
 107                 continue;
 108             }
 109             pcmk__add_word(&metal_list, &metal_list_len, node->details->uname);
 110         }
 111     }
 112 
 113     *uname = node_list;
 114     if(metal) {
 115         *metal = metal_list;
 116     }
 117 }
 118 
 119 /*!
 120  * \internal
 121  * \brief Separate a list of notification entries into resource and node strings
 122  *
 123  * \param[in,out] list       List of notify_entry_t* (will be sorted here)
 124  * \param[out]    rsc_list   String list of clone instances from \p list
 125  * \param[out]    node_list  String list of nodes from \p list
 126  *
 127  * \return (Possibly new head of) sorted \p list
 128  */
 129 static GList *
 130 expand_list(GList *list, char **rsc_list, char **node_list)
     /* [previous][next][first][last][top][bottom][index][help] */
 131 {
 132     const char *last_rsc_id = NULL;
 133     size_t rsc_list_len = 0;
 134     size_t node_list_len = 0;
 135 
 136     CRM_CHECK(rsc_list != NULL, return list);
 137 
 138     // If there are no entries, return "empty" lists
 139     if (list == NULL) {
 140         *rsc_list = strdup(" ");
 141         if (node_list) {
 142             *node_list = strdup(" ");
 143         }
 144         return list;
 145     }
 146 
 147     // Initialize output lists to NULL
 148     *rsc_list = NULL;
 149     if (node_list) {
 150         *node_list = NULL;
 151     }
 152 
 153     // Sort input list for user-friendliness (and ease of filtering duplicates)
 154     list = g_list_sort(list, sort_notify_entries);
 155 
 156     for (GList *gIter = list; gIter != NULL; gIter = gIter->next) {
 157         notify_entry_t *entry = (notify_entry_t *) gIter->data;
 158 
 159         // Entry must have a resource (with ID)
 160         CRM_LOG_ASSERT((entry != NULL) && (entry->rsc != NULL)
 161                        && (entry->rsc->id != NULL));
 162         if ((entry == NULL) || (entry->rsc == NULL)
 163             || (entry->rsc->id == NULL)) {
 164             continue;
 165         }
 166 
 167         // Entry must have a node unless listing inactive resources
 168         CRM_LOG_ASSERT((node_list == NULL) || (entry->node != NULL));
 169         if ((node_list != NULL) && (entry->node == NULL)) {
 170             continue;
 171         }
 172 
 173         // Don't add duplicates of a particular clone instance
 174         if (pcmk__str_eq(entry->rsc->id, last_rsc_id, pcmk__str_none)) {
 175             continue;
 176         }
 177         last_rsc_id = entry->rsc->id;
 178         pcmk__add_word(rsc_list, &rsc_list_len, entry->rsc->id);
 179         if ((node_list != NULL) && (entry->node->details->uname != NULL)) {
 180             pcmk__add_word(node_list, &node_list_len,
 181                            entry->node->details->uname);
 182         }
 183     }
 184     return list;
 185 }
 186 
 187 static void
 188 dup_attr(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 189 {
 190     add_hash_param(user_data, key, value);
 191 }
 192 
 193 static void
 194 add_notify_data_to_action_meta(notify_data_t *n_data, pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
 195 {
 196     for (GSList *item = n_data->keys; item; item = item->next) {
 197         pcmk_nvpair_t *nvpair = item->data;
 198 
 199         add_hash_param(action->meta, nvpair->name, nvpair->value);
 200     }
 201 }
 202 
 203 static pe_action_t *
 204 pe_notify(pe_resource_t * rsc, pe_node_t * node, pe_action_t * op, pe_action_t * confirm,
     /* [previous][next][first][last][top][bottom][index][help] */
 205           notify_data_t * n_data, pe_working_set_t * data_set)
 206 {
 207     char *key = NULL;
 208     pe_action_t *trigger = NULL;
 209     const char *value = NULL;
 210     const char *task = NULL;
 211 
 212     if (op == NULL || confirm == NULL) {
 213         pe_rsc_trace(rsc, "Op=%p confirm=%p", op, confirm);
 214         return NULL;
 215     }
 216 
 217     CRM_CHECK(rsc != NULL, return NULL);
 218     CRM_CHECK(node != NULL, return NULL);
 219 
 220     if (node->details->online == FALSE) {
 221         pe_rsc_trace(rsc, "Skipping notification for %s: node offline", rsc->id);
 222         return NULL;
 223     } else if (!pcmk_is_set(op->flags, pe_action_runnable)) {
 224         pe_rsc_trace(rsc, "Skipping notification for %s: not runnable", op->uuid);
 225         return NULL;
 226     }
 227 
 228     value = g_hash_table_lookup(op->meta, "notify_type");
 229     task = g_hash_table_lookup(op->meta, "notify_operation");
 230 
 231     pe_rsc_trace(rsc, "Creating notify actions for %s: %s (%s-%s)", op->uuid, rsc->id, value, task);
 232 
 233     key = pcmk__notify_key(rsc->id, value, task);
 234     trigger = custom_action(rsc, key, op->task, node,
 235                             pcmk_is_set(op->flags, pe_action_optional),
 236                             TRUE, data_set);
 237     g_hash_table_foreach(op->meta, dup_attr, trigger->meta);
 238     add_notify_data_to_action_meta(n_data, trigger);
 239 
 240     /* pseudo_notify before notify */
 241     pe_rsc_trace(rsc, "Ordering %s before %s (%d->%d)", op->uuid, trigger->uuid, trigger->id,
 242                  op->id);
 243 
 244     order_actions(op, trigger, pe_order_optional);
 245     order_actions(trigger, confirm, pe_order_optional);
 246     return trigger;
 247 }
 248 
 249 static void
 250 pe_post_notify(pe_resource_t * rsc, pe_node_t * node, notify_data_t * n_data, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 251 {
 252     pe_action_t *notify = NULL;
 253 
 254     CRM_CHECK(rsc != NULL, return);
 255 
 256     if (n_data->post == NULL) {
 257         return;                 /* Nothing to do */
 258     }
 259 
 260     notify = pe_notify(rsc, node, n_data->post, n_data->post_done, n_data, data_set);
 261 
 262     if (notify != NULL) {
 263         notify->priority = INFINITY;
 264     }
 265 
 266     if (n_data->post_done) {
 267         GListPtr gIter = rsc->actions;
 268 
 269         for (; gIter != NULL; gIter = gIter->next) {
 270             pe_action_t *mon = (pe_action_t *) gIter->data;
 271             const char *interval_ms_s = g_hash_table_lookup(mon->meta,
 272                                                             XML_LRM_ATTR_INTERVAL_MS);
 273 
 274             if (pcmk__str_eq(interval_ms_s, "0", pcmk__str_null_matches | pcmk__str_casei)) {
 275                 pe_rsc_trace(rsc, "Skipping %s: interval", mon->uuid);
 276                 continue;
 277             } else if (pcmk__str_eq(mon->task, RSC_CANCEL, pcmk__str_casei)) {
 278                 pe_rsc_trace(rsc, "Skipping %s: cancel", mon->uuid);
 279                 continue;
 280             }
 281 
 282             order_actions(n_data->post_done, mon, pe_order_optional);
 283         }
 284     }
 285 }
 286 
 287 notify_data_t *
 288 create_notification_boundaries(pe_resource_t * rsc, const char *action, pe_action_t * start,
     /* [previous][next][first][last][top][bottom][index][help] */
 289                                pe_action_t * end, pe_working_set_t * data_set)
 290 {
 291     /* Create the pseudo ops that precede and follow the actual notifications */
 292 
 293     /*
 294      * Creates two sequences (conditional on start and end being supplied):
 295      *   pre_notify -> pre_notify_complete -> start, and
 296      *   end -> post_notify -> post_notify_complete
 297      *
 298      * 'start' and 'end' may be the same event or ${X} and ${X}ed as per clones
 299      */
 300     char *key = NULL;
 301     notify_data_t *n_data = NULL;
 302 
 303     if (!pcmk_is_set(rsc->flags, pe_rsc_notify)) {
 304         return NULL;
 305     }
 306 
 307     n_data = calloc(1, sizeof(notify_data_t));
 308     n_data->action = action;
 309 
 310     if (start) {
 311         /* create pre-event notification wrappers */
 312         key = pcmk__notify_key(rsc->id, "pre", start->task);
 313         n_data->pre =
 314             custom_action(rsc, key, RSC_NOTIFY, NULL,
 315                           pcmk_is_set(start->flags, pe_action_optional),
 316                           TRUE, data_set);
 317 
 318         update_action_flags(n_data->pre, pe_action_pseudo, __func__, __LINE__);
 319         update_action_flags(n_data->pre, pe_action_runnable, __func__,
 320                             __LINE__);
 321 
 322         add_hash_param(n_data->pre->meta, "notify_type", "pre");
 323         add_hash_param(n_data->pre->meta, "notify_operation", n_data->action);
 324 
 325         add_hash_param(n_data->pre->meta, "notify_key_type", "pre");
 326         add_hash_param(n_data->pre->meta, "notify_key_operation", start->task);
 327 
 328         /* create pre_notify_complete */
 329         key = pcmk__notify_key(rsc->id, "confirmed-pre", start->task);
 330         n_data->pre_done = custom_action(rsc, key, RSC_NOTIFIED, NULL,
 331                                          pcmk_is_set(start->flags, pe_action_optional),
 332                                          TRUE, data_set);
 333 
 334         update_action_flags(n_data->pre_done, pe_action_pseudo, __func__,
 335                             __LINE__);
 336         update_action_flags(n_data->pre_done, pe_action_runnable, __func__,
 337                             __LINE__);
 338 
 339         add_hash_param(n_data->pre_done->meta, "notify_type", "pre");
 340         add_hash_param(n_data->pre_done->meta, "notify_operation", n_data->action);
 341 
 342         add_hash_param(n_data->pre_done->meta, "notify_key_type", "confirmed-pre");
 343         add_hash_param(n_data->pre_done->meta, "notify_key_operation", start->task);
 344 
 345         order_actions(n_data->pre_done, start, pe_order_optional);
 346         order_actions(n_data->pre, n_data->pre_done, pe_order_optional);
 347     }
 348 
 349     if (end) {
 350         /* create post-event notification wrappers */
 351         key = pcmk__notify_key(rsc->id, "post", end->task);
 352         n_data->post = custom_action(rsc, key, RSC_NOTIFY, NULL,
 353                                      pcmk_is_set(end->flags, pe_action_optional),
 354                                      TRUE, data_set);
 355 
 356         n_data->post->priority = INFINITY;
 357         update_action_flags(n_data->post, pe_action_pseudo, __func__,
 358                             __LINE__);
 359         if (pcmk_is_set(end->flags, pe_action_runnable)) {
 360             update_action_flags(n_data->post, pe_action_runnable, __func__,
 361                                 __LINE__);
 362         } else {
 363             update_action_flags(n_data->post, pe_action_runnable | pe_action_clear,
 364                                 __func__, __LINE__);
 365         }
 366 
 367         add_hash_param(n_data->post->meta, "notify_type", "post");
 368         add_hash_param(n_data->post->meta, "notify_operation", n_data->action);
 369 
 370         add_hash_param(n_data->post->meta, "notify_key_type", "post");
 371         add_hash_param(n_data->post->meta, "notify_key_operation", end->task);
 372 
 373         /* create post_notify_complete */
 374         key = pcmk__notify_key(rsc->id, "confirmed-post", end->task);
 375         n_data->post_done = custom_action(rsc, key, RSC_NOTIFIED, NULL,
 376                                           pcmk_is_set(end->flags, pe_action_optional),
 377                                           TRUE, data_set);
 378 
 379         n_data->post_done->priority = INFINITY;
 380         update_action_flags(n_data->post_done, pe_action_pseudo, __func__,
 381                             __LINE__);
 382         if (pcmk_is_set(end->flags, pe_action_runnable)) {
 383             update_action_flags(n_data->post_done, pe_action_runnable,
 384                                 __func__, __LINE__);
 385         } else {
 386             update_action_flags(n_data->post_done, pe_action_runnable | pe_action_clear,
 387                                 __func__, __LINE__);
 388         }
 389 
 390         add_hash_param(n_data->post_done->meta, "notify_type", "post");
 391         add_hash_param(n_data->post_done->meta, "notify_operation", n_data->action);
 392 
 393         add_hash_param(n_data->post_done->meta, "notify_key_type", "confirmed-post");
 394         add_hash_param(n_data->post_done->meta, "notify_key_operation", end->task);
 395 
 396         order_actions(end, n_data->post, pe_order_implies_then);
 397         order_actions(n_data->post, n_data->post_done, pe_order_implies_then);
 398     }
 399 
 400     if (start && end) {
 401         order_actions(n_data->pre_done, n_data->post, pe_order_optional);
 402     }
 403     return n_data;
 404 }
 405 
 406 void
 407 collect_notification_data(pe_resource_t * rsc, gboolean state, gboolean activity,
     /* [previous][next][first][last][top][bottom][index][help] */
 408                           notify_data_t * n_data)
 409 {
 410 
 411     if(n_data->allowed_nodes == NULL) {
 412         n_data->allowed_nodes = rsc->allowed_nodes;
 413     }
 414 
 415     if (rsc->children) {
 416         GListPtr gIter = rsc->children;
 417 
 418         for (; gIter != NULL; gIter = gIter->next) {
 419             pe_resource_t *child = (pe_resource_t *) gIter->data;
 420 
 421             collect_notification_data(child, state, activity, n_data);
 422         }
 423         return;
 424     }
 425 
 426     if (state) {
 427         notify_entry_t *entry = NULL;
 428 
 429         entry = calloc(1, sizeof(notify_entry_t));
 430         entry->rsc = rsc;
 431         if (rsc->running_on) {
 432             /* we only take the first one */
 433             entry->node = rsc->running_on->data;
 434         }
 435 
 436         pe_rsc_trace(rsc, "%s state: %s", rsc->id, role2text(rsc->role));
 437 
 438         switch (rsc->role) {
 439             case RSC_ROLE_STOPPED:
 440                 n_data->inactive = g_list_prepend(n_data->inactive, entry);
 441                 break;
 442             case RSC_ROLE_STARTED:
 443                 n_data->active = g_list_prepend(n_data->active, entry);
 444                 break;
 445             case RSC_ROLE_SLAVE:
 446                 n_data->slave = g_list_prepend(n_data->slave, entry);
 447                 n_data->active = g_list_prepend(n_data->active,
 448                                                 dup_notify_entry(entry));
 449                 break;
 450             case RSC_ROLE_MASTER:
 451                 n_data->master = g_list_prepend(n_data->master, entry);
 452                 n_data->active = g_list_prepend(n_data->active,
 453                                                 dup_notify_entry(entry));
 454                 break;
 455             default:
 456                 crm_err("Unsupported notify role");
 457                 free(entry);
 458                 break;
 459         }
 460     }
 461 
 462     if (activity) {
 463         notify_entry_t *entry = NULL;
 464         enum action_tasks task;
 465 
 466         GListPtr gIter = rsc->actions;
 467 
 468         for (; gIter != NULL; gIter = gIter->next) {
 469             pe_action_t *op = (pe_action_t *) gIter->data;
 470 
 471             if (!pcmk_is_set(op->flags, pe_action_optional)
 472                 && (op->node != NULL)) {
 473 
 474                 task = text2task(op->task);
 475 
 476                 if(task == stop_rsc && op->node->details->unclean) {
 477                     // Create anyway (additional noise if node can't be fenced)
 478                 } else if (!pcmk_is_set(op->flags, pe_action_runnable)) {
 479                     continue;
 480                 }
 481 
 482                 entry = calloc(1, sizeof(notify_entry_t));
 483                 entry->node = op->node;
 484                 entry->rsc = rsc;
 485 
 486                 switch (task) {
 487                     case start_rsc:
 488                         n_data->start = g_list_prepend(n_data->start, entry);
 489                         break;
 490                     case stop_rsc:
 491                         n_data->stop = g_list_prepend(n_data->stop, entry);
 492                         break;
 493                     case action_promote:
 494                         n_data->promote = g_list_prepend(n_data->promote, entry);
 495                         break;
 496                     case action_demote:
 497                         n_data->demote = g_list_prepend(n_data->demote, entry);
 498                         break;
 499                     default:
 500                         free(entry);
 501                         break;
 502                 }
 503             }
 504         }
 505     }
 506 }
 507 
 508 #define add_notify_env(n_data, key, value) do {                         \
 509          n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, value);  \
 510     } while (0)
 511 
 512 #define add_notify_env_free(n_data, key, value) do {                    \
 513          n_data->keys = pcmk_prepend_nvpair(n_data->keys, key, value);  \
 514          free(value); value = NULL;                                     \
 515     } while (0)
 516 
 517 /*!
 518  * \internal
 519  * \brief Create notification name/value pairs from raw data
 520  *
 521  * \param[in]     rsc       Resource that notification is for
 522  * \param[in,out] n_data    Notification data
 523  * \param[in]     data_set  Cluster working set
 524  */
 525 void
 526 pcmk__create_notification_keys(pe_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 527                                notify_data_t *n_data,
 528                                pe_working_set_t *data_set)
 529 {
 530     bool required = false; // Whether to make notify actions required
 531     char *rsc_list = NULL;
 532     char *node_list = NULL;
 533     char *metal_list = NULL;
 534     const char *source = NULL;
 535     GListPtr nodes = NULL;
 536 
 537     n_data->stop = expand_list(n_data->stop, &rsc_list, &node_list);
 538     if (!pcmk__str_eq(" ", rsc_list, pcmk__str_null_matches)
 539         && pcmk__str_eq(n_data->action, RSC_STOP, pcmk__str_casei)) {
 540         required = true;
 541     }
 542     add_notify_env_free(n_data, "notify_stop_resource", rsc_list);
 543     add_notify_env_free(n_data, "notify_stop_uname", node_list);
 544 
 545     if ((n_data->start != NULL)
 546         && pcmk__str_eq(n_data->action, RSC_START, pcmk__str_casei)) {
 547         required = true;
 548     }
 549     n_data->start = expand_list(n_data->start, &rsc_list, &node_list);
 550     add_notify_env_free(n_data, "notify_start_resource", rsc_list);
 551     add_notify_env_free(n_data, "notify_start_uname", node_list);
 552 
 553     if ((n_data->demote != NULL)
 554         && pcmk__str_eq(n_data->action, RSC_DEMOTE, pcmk__str_casei)) {
 555         required = true;
 556     }
 557     n_data->demote = expand_list(n_data->demote, &rsc_list, &node_list);
 558     add_notify_env_free(n_data, "notify_demote_resource", rsc_list);
 559     add_notify_env_free(n_data, "notify_demote_uname", node_list);
 560 
 561     if ((n_data->promote != NULL)
 562         && pcmk__str_eq(n_data->action, RSC_PROMOTE, pcmk__str_casei)) {
 563         required = true;
 564     }
 565     n_data->promote = expand_list(n_data->promote, &rsc_list, &node_list);
 566     add_notify_env_free(n_data, "notify_promote_resource", rsc_list);
 567     add_notify_env_free(n_data, "notify_promote_uname", node_list);
 568 
 569     n_data->active = expand_list(n_data->active, &rsc_list, &node_list);
 570     add_notify_env_free(n_data, "notify_active_resource", rsc_list);
 571     add_notify_env_free(n_data, "notify_active_uname", node_list);
 572 
 573     n_data->slave = expand_list(n_data->slave, &rsc_list, &node_list);
 574     add_notify_env_free(n_data, "notify_slave_resource", rsc_list);
 575     add_notify_env_free(n_data, "notify_slave_uname", node_list);
 576 
 577     n_data->master = expand_list(n_data->master, &rsc_list, &node_list);
 578     add_notify_env_free(n_data, "notify_master_resource", rsc_list);
 579     add_notify_env_free(n_data, "notify_master_uname", node_list);
 580 
 581     n_data->inactive = expand_list(n_data->inactive, &rsc_list, NULL);
 582     add_notify_env_free(n_data, "notify_inactive_resource", rsc_list);
 583 
 584     nodes = g_hash_table_get_values(n_data->allowed_nodes);
 585     if (pcmk_is_set(data_set->flags, pe_flag_stdout)) {
 586         /* If printing to stdout, sort the node list, for consistent
 587          * regression test output (while avoiding the performance hit
 588          * for the live cluster).
 589          */
 590         nodes = g_list_sort(nodes, sort_node_uname);
 591     }
 592     expand_node_list(nodes, &node_list, NULL);
 593     add_notify_env_free(n_data, "notify_available_uname", node_list);
 594     g_list_free(nodes);
 595 
 596     source = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET);
 597     if (pcmk__str_eq("host", source, pcmk__str_casei)) {
 598         expand_node_list(data_set->nodes, &node_list, &metal_list);
 599         add_notify_env_free(n_data, "notify_all_hosts", metal_list);
 600     } else {
 601         expand_node_list(data_set->nodes, &node_list, NULL);
 602     }
 603     add_notify_env_free(n_data, "notify_all_uname", node_list);
 604 
 605     if (required && n_data->pre) {
 606         update_action_flags(n_data->pre, pe_action_optional | pe_action_clear,
 607                             __func__, __LINE__);
 608         update_action_flags(n_data->pre_done, pe_action_optional | pe_action_clear,
 609                             __func__, __LINE__);
 610     }
 611 
 612     if (required && n_data->post) {
 613         update_action_flags(n_data->post, pe_action_optional | pe_action_clear,
 614                             __func__, __LINE__);
 615         update_action_flags(n_data->post_done, pe_action_optional | pe_action_clear,
 616                             __func__, __LINE__);
 617     }
 618 }
 619 
 620 /*
 621  * \internal
 622  * \brief Find any remote connection start relevant to an action
 623  *
 624  * \param[in] action  Action to chek
 625  *
 626  * \return If action is behind a remote connection, connection's start
 627  */
 628 static pe_action_t *
 629 find_remote_start(pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
 630 {
 631     if (action && action->node) {
 632         pe_resource_t *remote_rsc = action->node->details->remote_rsc;
 633 
 634         if (remote_rsc) {
 635             return find_first_action(remote_rsc->actions, NULL, RSC_START,
 636                                      NULL);
 637         }
 638     }
 639     return NULL;
 640 }
 641 
 642 void
 643 create_notifications(pe_resource_t * rsc, notify_data_t * n_data, pe_working_set_t * data_set)
     /* [previous][next][first][last][top][bottom][index][help] */
 644 {
 645     GListPtr gIter = NULL;
 646     pe_action_t *stop = NULL;
 647     pe_action_t *start = NULL;
 648     enum action_tasks task = text2task(n_data->action);
 649 
 650     if (rsc->children) {
 651         gIter = rsc->children;
 652         for (; gIter != NULL; gIter = gIter->next) {
 653             pe_resource_t *child = (pe_resource_t *) gIter->data;
 654 
 655             create_notifications(child, n_data, data_set);
 656         }
 657         return;
 658     }
 659 
 660     /* Copy notification details into standard ops */
 661 
 662     for (gIter = rsc->actions; gIter != NULL; gIter = gIter->next) {
 663         pe_action_t *op = (pe_action_t *) gIter->data;
 664 
 665         if (!pcmk_is_set(op->flags, pe_action_optional)
 666             && (op->node != NULL)) {
 667 
 668             enum action_tasks t = text2task(op->task);
 669 
 670             switch (t) {
 671                 case start_rsc:
 672                 case stop_rsc:
 673                 case action_promote:
 674                 case action_demote:
 675                     add_notify_data_to_action_meta(n_data, op);
 676                     break;
 677                 default:
 678                     break;
 679             }
 680         }
 681     }
 682 
 683     switch (task) {
 684         case start_rsc:
 685             if (n_data->start == NULL) {
 686                 pe_rsc_trace(rsc, "Skipping empty notification for: %s.%s (%s->%s)",
 687                              n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
 688                 return;
 689             }
 690             break;
 691         case action_promote:
 692             if (n_data->promote == NULL) {
 693                 pe_rsc_trace(rsc, "Skipping empty notification for: %s.%s (%s->%s)",
 694                              n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
 695                 return;
 696             }
 697             break;
 698         case action_demote:
 699             if (n_data->demote == NULL) {
 700                 pe_rsc_trace(rsc, "Skipping empty notification for: %s.%s (%s->%s)",
 701                              n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
 702                 return;
 703             }
 704             break;
 705         default:
 706             /* We cannot do the same for stop_rsc/n_data->stop at it
 707              * might be implied by fencing
 708              */
 709             break;
 710     }
 711 
 712     pe_rsc_trace(rsc, "Creating notifications for: %s.%s (%s->%s)",
 713                  n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
 714 
 715     stop = find_first_action(rsc->actions, NULL, RSC_STOP, NULL);
 716     start = find_first_action(rsc->actions, NULL, RSC_START, NULL);
 717 
 718     /* stop / demote */
 719     if (rsc->role != RSC_ROLE_STOPPED) {
 720         if (task == stop_rsc || task == action_demote) {
 721             gIter = rsc->running_on;
 722             for (; gIter != NULL; gIter = gIter->next) {
 723                 pe_node_t *current_node = (pe_node_t *) gIter->data;
 724 
 725                 /* if this stop action is a pseudo action as a result of the current
 726                  * node being fenced, this stop action is implied by the fencing 
 727                  * action. There's no reason to send the fenced node a stop notification */ 
 728                 if (stop && pcmk_is_set(stop->flags, pe_action_pseudo) &&
 729                     (current_node->details->unclean || current_node->details->remote_requires_reset) ) {
 730 
 731                     continue;
 732                 }
 733 
 734                 pe_notify(rsc, current_node, n_data->pre, n_data->pre_done, n_data, data_set);
 735                 if (task == action_demote || stop == NULL
 736                     || pcmk_is_set(stop->flags, pe_action_optional)) {
 737                     pe_post_notify(rsc, current_node, n_data, data_set);
 738                 }
 739             }
 740         }
 741     }
 742 
 743     /* start / promote */
 744     if (rsc->next_role != RSC_ROLE_STOPPED) {
 745         if (rsc->allocated_to == NULL) {
 746             pe_proc_err("Next role '%s' but %s is not allocated", role2text(rsc->next_role),
 747                         rsc->id);
 748 
 749         } else if (task == start_rsc || task == action_promote) {
 750 
 751             if (start) {
 752                 pe_action_t *remote_start = find_remote_start(start);
 753 
 754                 if (remote_start
 755                     && !pcmk_is_set(remote_start->flags, pe_action_runnable)) {
 756                     /* Start and promote actions for a clone instance behind
 757                      * a Pacemaker Remote connection happen after the
 758                      * connection starts. If the connection start is blocked, do
 759                      * not schedule notifications for these actions.
 760                      */
 761                     return;
 762                 }
 763             }
 764             if ((task != start_rsc) || (start == NULL)
 765                 || pcmk_is_set(start->flags, pe_action_optional)) {
 766 
 767                 pe_notify(rsc, rsc->allocated_to, n_data->pre, n_data->pre_done, n_data, data_set);
 768             }
 769             pe_post_notify(rsc, rsc->allocated_to, n_data, data_set);
 770         }
 771     }
 772 }
 773 
 774 void
 775 free_notification_data(notify_data_t * n_data)
     /* [previous][next][first][last][top][bottom][index][help] */
 776 {
 777     if (n_data == NULL) {
 778         return;
 779     }
 780 
 781     g_list_free_full(n_data->stop, free);
 782     g_list_free_full(n_data->start, free);
 783     g_list_free_full(n_data->demote, free);
 784     g_list_free_full(n_data->promote, free);
 785     g_list_free_full(n_data->master, free);
 786     g_list_free_full(n_data->slave, free);
 787     g_list_free_full(n_data->active, free);
 788     g_list_free_full(n_data->inactive, free);
 789     pcmk_free_nvpairs(n_data->keys);
 790     free(n_data);
 791 }
 792 
 793 void
 794 create_secondary_notification(pe_action_t *action, pe_resource_t *rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
 795                               pe_action_t *stonith_op,
 796                               pe_working_set_t *data_set)
 797 {
 798     notify_data_t *n_data;
 799 
 800     crm_info("Creating secondary notification for %s", action->uuid);
 801     n_data = create_notification_boundaries(rsc, RSC_STOP, NULL, stonith_op,
 802                                             data_set);
 803     collect_notification_data(rsc, TRUE, FALSE, n_data);
 804     add_notify_env(n_data, "notify_stop_resource", rsc->id);
 805     add_notify_env(n_data, "notify_stop_uname", action->node->details->uname);
 806     create_notifications(uber_parent(rsc), n_data, data_set);
 807     free_notification_data(n_data);
 808 }

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