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. trigger_graph_processing
  4. abort_timer_popped
  5. abort_after_delay
  6. abort2text
  7. update_abort_priority
  8. abort_transition_graph

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

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