root/pengine/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. pe_notify
  7. pe_post_notify
  8. create_notification_boundaries
  9. collect_notification_data
  10. expand_notification_data
  11. create_notifications
  12. free_notification_data
  13. create_secondary_notification

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

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