root/daemons/controld/controld_te_utils.c

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

DEFINITIONS

This source file includes following definitions.
  1. stop_te_timer
  2. te_graph_trigger
  3. controld_init_transition_trigger
  4. controld_destroy_transition_trigger
  5. controld_trigger_graph_as
  6. abort_timer_popped
  7. abort_after_delay
  8. abort2text
  9. update_abort_priority
  10. abort_transition_graph

   1 /*
   2  * Copyright 2004-2022 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/crm.h>
  12 #include <crm/msg_xml.h>
  13 #include <crm/common/xml.h>
  14 
  15 #include <pacemaker-controld.h>
  16 
  17 //! Triggers transition graph processing
  18 static crm_trigger_t *transition_trigger = NULL;
  19 
  20 gboolean
  21 stop_te_timer(pcmk__graph_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
  22 {
  23     if (action == NULL) {
  24         return FALSE;
  25     }
  26     if (action->timer != 0) {
  27         crm_trace("Stopping action timer");
  28         g_source_remove(action->timer);
  29         action->timer = 0;
  30     } else {
  31         crm_trace("Action timer was already stopped");
  32         return FALSE;
  33     }
  34     return TRUE;
  35 }
  36 
  37 static gboolean
  38 te_graph_trigger(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  39 {
  40     if (controld_globals.transition_graph == NULL) {
  41         crm_debug("Nothing to do");
  42         return TRUE;
  43     }
  44 
  45     crm_trace("Invoking graph %d in state %s",
  46               controld_globals.transition_graph->id,
  47               fsa_state2string(controld_globals.fsa_state));
  48 
  49     switch (controld_globals.fsa_state) {
  50         case S_STARTING:
  51         case S_PENDING:
  52         case S_NOT_DC:
  53         case S_HALT:
  54         case S_ILLEGAL:
  55         case S_STOPPING:
  56         case S_TERMINATE:
  57             return TRUE;
  58         default:
  59             break;
  60     }
  61 
  62     if (!controld_globals.transition_graph->complete) {
  63         enum pcmk__graph_status graph_rc;
  64         int orig_limit = controld_globals.transition_graph->batch_limit;
  65         int throttled_limit = throttle_get_total_job_limit(orig_limit);
  66 
  67         controld_globals.transition_graph->batch_limit = throttled_limit;
  68         graph_rc = pcmk__execute_graph(controld_globals.transition_graph);
  69         controld_globals.transition_graph->batch_limit = orig_limit;
  70 
  71         if (graph_rc == pcmk__graph_active) {
  72             crm_trace("Transition not yet complete");
  73             return TRUE;
  74 
  75         } else if (graph_rc == pcmk__graph_pending) {
  76             crm_trace("Transition not yet complete - no actions fired");
  77             return TRUE;
  78         }
  79 
  80         if (graph_rc != pcmk__graph_complete) {
  81             crm_warn("Transition failed: %s",
  82                      pcmk__graph_status2text(graph_rc));
  83             pcmk__log_graph(LOG_NOTICE, controld_globals.transition_graph);
  84         }
  85     }
  86 
  87     crm_debug("Transition %d is now complete",
  88               controld_globals.transition_graph->id);
  89     controld_globals.transition_graph->complete = true;
  90     notify_crmd(controld_globals.transition_graph);
  91 
  92     return TRUE;
  93 }
  94 
  95 /*!
  96  * \internal
  97  * \brief Initialize transition trigger
  98  */
  99 void
 100 controld_init_transition_trigger(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 101 {
 102     transition_trigger = mainloop_add_trigger(G_PRIORITY_LOW, te_graph_trigger,
 103                                               NULL);
 104 }
 105 
 106 /*!
 107  * \internal
 108  * \brief Destroy transition trigger
 109  */
 110 void
 111 controld_destroy_transition_trigger(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113     mainloop_destroy_trigger(transition_trigger);
 114     transition_trigger = NULL;
 115 }
 116 
 117 void
 118 controld_trigger_graph_as(const char *fn, int line)
     /* [previous][next][first][last][top][bottom][index][help] */
 119 {
 120     crm_trace("%s:%d - Triggered graph processing", fn, line);
 121     mainloop_set_trigger(transition_trigger);
 122 }
 123 
 124 static struct abort_timer_s {
 125     bool aborted;
 126     guint id;
 127     int priority;
 128     enum pcmk__graph_next action;
 129     const char *text;
 130 } abort_timer = { 0, };
 131 
 132 static gboolean
 133 abort_timer_popped(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135     if (AM_I_DC && (abort_timer.aborted == FALSE)) {
 136         abort_transition(abort_timer.priority, abort_timer.action,
 137                          abort_timer.text, NULL);
 138     }
 139     abort_timer.id = 0;
 140     return FALSE; // do not immediately reschedule timer
 141 }
 142 
 143 /*!
 144  * \internal
 145  * \brief Abort transition after delay, if not already aborted in that time
 146  *
 147  * \param[in] abort_text  Must be literal string
 148  */
 149 void
 150 abort_after_delay(int abort_priority, enum pcmk__graph_next abort_action,
     /* [previous][next][first][last][top][bottom][index][help] */
 151                   const char *abort_text, guint delay_ms)
 152 {
 153     if (abort_timer.id) {
 154         // Timer already in progress, stop and reschedule
 155         g_source_remove(abort_timer.id);
 156     }
 157     abort_timer.aborted = FALSE;
 158     abort_timer.priority = abort_priority;
 159     abort_timer.action = abort_action;
 160     abort_timer.text = abort_text;
 161     abort_timer.id = g_timeout_add(delay_ms, abort_timer_popped, NULL);
 162 }
 163 
 164 static const char *
 165 abort2text(enum pcmk__graph_next abort_action)
     /* [previous][next][first][last][top][bottom][index][help] */
 166 {
 167     switch (abort_action) {
 168         case pcmk__graph_done:      return "done";
 169         case pcmk__graph_wait:      return "stop";
 170         case pcmk__graph_restart:   return "restart";
 171         case pcmk__graph_shutdown:  return "shutdown";
 172     }
 173     return "unknown";
 174 }
 175 
 176 static bool
 177 update_abort_priority(pcmk__graph_t *graph, int priority,
     /* [previous][next][first][last][top][bottom][index][help] */
 178                       enum pcmk__graph_next action, const char *abort_reason)
 179 {
 180     bool change = FALSE;
 181 
 182     if (graph == NULL) {
 183         return change;
 184     }
 185 
 186     if (graph->abort_priority < priority) {
 187         crm_debug("Abort priority upgraded from %d to %d", graph->abort_priority, priority);
 188         graph->abort_priority = priority;
 189         if (graph->abort_reason != NULL) {
 190             crm_debug("'%s' abort superseded by %s", graph->abort_reason, abort_reason);
 191         }
 192         graph->abort_reason = abort_reason;
 193         change = TRUE;
 194     }
 195 
 196     if (graph->completion_action < action) {
 197         crm_debug("Abort action %s superseded by %s: %s",
 198                   abort2text(graph->completion_action), abort2text(action), abort_reason);
 199         graph->completion_action = action;
 200         change = TRUE;
 201     }
 202 
 203     return change;
 204 }
 205 
 206 void
 207 abort_transition_graph(int abort_priority, enum pcmk__graph_next abort_action,
     /* [previous][next][first][last][top][bottom][index][help] */
 208                        const char *abort_text, const xmlNode *reason,
 209                        const char *fn, int line)
 210 {
 211     int add[] = { 0, 0, 0 };
 212     int del[] = { 0, 0, 0 };
 213     int level = LOG_INFO;
 214     const xmlNode *diff = NULL;
 215     const xmlNode *change = NULL;
 216 
 217     CRM_CHECK(controld_globals.transition_graph != NULL, return);
 218 
 219     switch (controld_globals.fsa_state) {
 220         case S_STARTING:
 221         case S_PENDING:
 222         case S_NOT_DC:
 223         case S_HALT:
 224         case S_ILLEGAL:
 225         case S_STOPPING:
 226         case S_TERMINATE:
 227             crm_info("Abort %s suppressed: state=%s (%scomplete)",
 228                      abort_text, fsa_state2string(controld_globals.fsa_state),
 229                      (controld_globals.transition_graph->complete? "" : "in"));
 230             return;
 231         default:
 232             break;
 233     }
 234 
 235     abort_timer.aborted = TRUE;
 236     controld_expect_sched_reply(NULL);
 237 
 238     if (!controld_globals.transition_graph->complete
 239         && update_abort_priority(controld_globals.transition_graph,
 240                                  abort_priority, abort_action,
 241                                  abort_text)) {
 242         level = LOG_NOTICE;
 243     }
 244 
 245     if (reason != NULL) {
 246         const xmlNode *search = NULL;
 247 
 248         for(search = reason; search; search = search->parent) {
 249             if (pcmk__str_eq(XML_TAG_DIFF, TYPE(search), pcmk__str_casei)) {
 250                 diff = search;
 251                 break;
 252             }
 253         }
 254 
 255         if(diff) {
 256             xml_patch_versions(diff, add, del);
 257             for(search = reason; search; search = search->parent) {
 258                 if (pcmk__str_eq(XML_DIFF_CHANGE, TYPE(search), pcmk__str_casei)) {
 259                     change = search;
 260                     break;
 261                 }
 262             }
 263         }
 264     }
 265 
 266     if (reason == NULL) {
 267         do_crm_log(level,
 268                    "Transition %d aborted: %s " CRM_XS " source=%s:%d "
 269                    "complete=%s", controld_globals.transition_graph->id,
 270                    abort_text, fn, line,
 271                    pcmk__btoa(controld_globals.transition_graph->complete));
 272 
 273     } else if(change == NULL) {
 274         GString *local_path = pcmk__element_xpath(reason);
 275         CRM_ASSERT(local_path != NULL);
 276 
 277         do_crm_log(level, "Transition %d aborted by %s.%s: %s "
 278                    CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
 279                    controld_globals.transition_graph->id, TYPE(reason),
 280                    ID(reason), abort_text, add[0], add[1], add[2], fn, line,
 281                    (const char *) local_path->str,
 282                    pcmk__btoa(controld_globals.transition_graph->complete));
 283         g_string_free(local_path, TRUE);
 284 
 285     } else {
 286         const char *kind = NULL;
 287         const char *op = crm_element_value(change, XML_DIFF_OP);
 288         const char *path = crm_element_value(change, XML_DIFF_PATH);
 289 
 290         if(change == reason) {
 291             if(strcmp(op, "create") == 0) {
 292                 reason = reason->children;
 293 
 294             } else if(strcmp(op, "modify") == 0) {
 295                 reason = first_named_child(reason, XML_DIFF_RESULT);
 296                 if(reason) {
 297                     reason = reason->children;
 298                 }
 299             }
 300         }
 301 
 302         kind = TYPE(reason);
 303         if(strcmp(op, "delete") == 0) {
 304             const char *shortpath = strrchr(path, '/');
 305 
 306             do_crm_log(level, "Transition %d aborted by deletion of %s: %s "
 307                        CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
 308                        controld_globals.transition_graph->id,
 309                        (shortpath? (shortpath + 1) : path), abort_text,
 310                        add[0], add[1], add[2], fn, line, path,
 311                        pcmk__btoa(controld_globals.transition_graph->complete));
 312 
 313         } else if (pcmk__str_eq(XML_CIB_TAG_NVPAIR, kind, pcmk__str_none)) {
 314             do_crm_log(level, "Transition %d aborted by %s doing %s %s=%s: %s "
 315                        CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
 316                        controld_globals.transition_graph->id,
 317                        crm_element_value(reason, XML_ATTR_ID), op,
 318                        crm_element_value(reason, XML_NVPAIR_ATTR_NAME),
 319                        crm_element_value(reason, XML_NVPAIR_ATTR_VALUE),
 320                        abort_text, add[0], add[1], add[2], fn, line, path,
 321                        pcmk__btoa(controld_globals.transition_graph->complete));
 322 
 323         } else if (pcmk__str_eq(XML_LRM_TAG_RSC_OP, kind, pcmk__str_none)) {
 324             const char *magic = crm_element_value(reason, XML_ATTR_TRANSITION_MAGIC);
 325 
 326             do_crm_log(level, "Transition %d aborted by operation %s '%s' on %s: %s "
 327                        CRM_XS " magic=%s cib=%d.%d.%d source=%s:%d complete=%s",
 328                        controld_globals.transition_graph->id,
 329                        crm_element_value(reason, XML_LRM_ATTR_TASK_KEY), op,
 330                        crm_element_value(reason, XML_LRM_ATTR_TARGET), abort_text,
 331                        magic, add[0], add[1], add[2], fn, line,
 332                        pcmk__btoa(controld_globals.transition_graph->complete));
 333 
 334         } else if (pcmk__str_any_of(kind, XML_CIB_TAG_STATE, XML_CIB_TAG_NODE, NULL)) {
 335             const char *uname = crm_peer_uname(ID(reason));
 336 
 337             do_crm_log(level, "Transition %d aborted by %s '%s' on %s: %s "
 338                        CRM_XS " cib=%d.%d.%d source=%s:%d complete=%s",
 339                        controld_globals.transition_graph->id,
 340                        kind, op, (uname? uname : ID(reason)), abort_text,
 341                        add[0], add[1], add[2], fn, line,
 342                        pcmk__btoa(controld_globals.transition_graph->complete));
 343 
 344         } else {
 345             const char *id = ID(reason);
 346 
 347             do_crm_log(level, "Transition %d aborted by %s.%s '%s': %s "
 348                        CRM_XS " cib=%d.%d.%d source=%s:%d path=%s complete=%s",
 349                        controld_globals.transition_graph->id,
 350                        TYPE(reason), (id? id : ""), (op? op : "change"),
 351                        abort_text, add[0], add[1], add[2], fn, line, path,
 352                        pcmk__btoa(controld_globals.transition_graph->complete));
 353         }
 354     }
 355 
 356     if (controld_globals.transition_graph->complete) {
 357         if (controld_get_period_transition_timer() > 0) {
 358             controld_stop_transition_timer();
 359             controld_start_transition_timer();
 360         } else {
 361             register_fsa_input(C_FSA_INTERNAL, I_PE_CALC, NULL);
 362         }
 363         return;
 364     }
 365 
 366     trigger_graph();
 367 }

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