root/daemons/attrd/attrd_utils.c

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

DEFINITIONS

This source file includes following definitions.
  1. attrd_set_requesting_shutdown
  2. attrd_clear_requesting_shutdown
  3. attrd_shutting_down
  4. attrd_shutdown
  5. attrd_init_mainloop
  6. attrd_run_mainloop
  7. attrd_value_needs_expansion
  8. attrd_expand_value
  9. attrd_failure_regex
  10. attrd_free_attribute_value
  11. attrd_free_attribute
  12. attrd_remove_peer_protocol_ver
  13. attrd_update_minimum_protocol_ver

   1 /*
   2  * Copyright 2004-2024 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <stdio.h>
  13 #include <stdbool.h>
  14 #include <errno.h>
  15 #include <glib.h>
  16 #include <regex.h>
  17 #include <sys/types.h>
  18 
  19 #include <crm/crm.h>
  20 #include <crm/common/ipc_internal.h>
  21 #include <crm/common/mainloop.h>
  22 #include <crm/common/xml.h>
  23 
  24 #include "pacemaker-attrd.h"
  25 
  26 cib_t *the_cib = NULL;
  27 
  28 static bool requesting_shutdown = false;
  29 static bool shutting_down = false;
  30 static GMainLoop *mloop = NULL;
  31 
  32 /* A hash table storing information on the protocol version of each peer attrd.
  33  * The key is the peer's uname, and the value is the protocol version number.
  34  */
  35 GHashTable *peer_protocol_vers = NULL;
  36 
  37 /*!
  38  * \internal
  39  * \brief  Set requesting_shutdown state
  40  */
  41 void
  42 attrd_set_requesting_shutdown(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  43 {
  44     requesting_shutdown = true;
  45 }
  46 
  47 /*!
  48  * \internal
  49  * \brief  Clear requesting_shutdown state
  50  */
  51 void
  52 attrd_clear_requesting_shutdown(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  53 {
  54     requesting_shutdown = false;
  55 }
  56 
  57 /*!
  58  * \internal
  59  * \brief Check whether local attribute manager is shutting down
  60  *
  61  * \param[in] if_requested  If \c true, also consider presence of
  62  *                          \c PCMK__NODE_ATTR_SHUTDOWN attribute
  63  *
  64  * \return \c true if local attribute manager has begun shutdown sequence
  65  *         or (if \p if_requested is \c true) whether local node has a nonzero
  66  *         \c PCMK__NODE_ATTR_SHUTDOWN attribute set, otherwise \c false
  67  * \note Most callers should pass \c false for \p if_requested, because the
  68  *       attribute manager needs to continue performing while the controller is
  69  *       shutting down, and even needs to be eligible for election in case all
  70  *       nodes are shutting down.
  71  */
  72 bool
  73 attrd_shutting_down(bool if_requested)
     /* [previous][next][first][last][top][bottom][index][help] */
  74 {
  75     return shutting_down || (if_requested && requesting_shutdown);
  76 }
  77 
  78 /*!
  79  * \internal
  80  * \brief  Exit (using mainloop or not, as appropriate)
  81  *
  82  * \param[in] nsig  Ignored
  83  */
  84 void
  85 attrd_shutdown(int nsig)
     /* [previous][next][first][last][top][bottom][index][help] */
  86 {
  87     // Tell various functions not to do anthing
  88     shutting_down = true;
  89 
  90     // Don't respond to signals while shutting down
  91     mainloop_destroy_signal(SIGTERM);
  92     mainloop_destroy_signal(SIGCHLD);
  93     mainloop_destroy_signal(SIGPIPE);
  94     mainloop_destroy_signal(SIGUSR1);
  95     mainloop_destroy_signal(SIGUSR2);
  96     mainloop_destroy_signal(SIGTRAP);
  97 
  98     attrd_free_waitlist();
  99     attrd_free_confirmations();
 100 
 101     if (peer_protocol_vers != NULL) {
 102         g_hash_table_destroy(peer_protocol_vers);
 103         peer_protocol_vers = NULL;
 104     }
 105 
 106     if ((mloop == NULL) || !g_main_loop_is_running(mloop)) {
 107         /* If there's no main loop active, just exit. This should be possible
 108          * only if we get SIGTERM in brief windows at start-up and shutdown.
 109          */
 110         crm_exit(CRM_EX_OK);
 111     } else {
 112         g_main_loop_quit(mloop);
 113         g_main_loop_unref(mloop);
 114     }
 115 }
 116 
 117 /*!
 118  * \internal
 119  * \brief Create a main loop for attrd
 120  */
 121 void
 122 attrd_init_mainloop(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 123 {
 124     mloop = g_main_loop_new(NULL, FALSE);
 125 }
 126 
 127 /*!
 128  * \internal
 129  * \brief Run attrd main loop
 130  */
 131 void
 132 attrd_run_mainloop(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 133 {
 134     g_main_loop_run(mloop);
 135 }
 136 
 137 /* strlen("value") */
 138 #define plus_plus_len (5)
 139 
 140 /*!
 141  * \internal
 142  * \brief  Check whether an attribute value should be expanded
 143  *
 144  * \param[in] value  Attribute value to check
 145  *
 146  * \return true if value needs expansion, false otherwise
 147  */
 148 bool
 149 attrd_value_needs_expansion(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 150 {
 151     return ((strlen(value) >= (plus_plus_len + 2))
 152            && (value[plus_plus_len] == '+')
 153            && ((value[plus_plus_len + 1] == '+')
 154                || (value[plus_plus_len + 1] == '=')));
 155 }
 156 
 157 /*!
 158  * \internal
 159  * \brief Expand an increment expression into an integer
 160  *
 161  * \param[in] value      Attribute increment expression to expand
 162  * \param[in] old_value  Previous value of attribute
 163  *
 164  * \return Expanded value
 165  */
 166 int
 167 attrd_expand_value(const char *value, const char *old_value)
     /* [previous][next][first][last][top][bottom][index][help] */
 168 {
 169     int offset = 1;
 170     int int_value = char2score(old_value);
 171 
 172     if (value[plus_plus_len + 1] != '+') {
 173         const char *offset_s = value + (plus_plus_len + 2);
 174 
 175         offset = char2score(offset_s);
 176     }
 177     int_value += offset;
 178 
 179     if (int_value > PCMK_SCORE_INFINITY) {
 180         int_value = PCMK_SCORE_INFINITY;
 181     }
 182     return int_value;
 183 }
 184 
 185 /*!
 186  * \internal
 187  * \brief Create regular expression matching failure-related attributes
 188  *
 189  * \param[out] regex  Where to store created regular expression
 190  * \param[in]  rsc    Name of resource to clear (or NULL for all)
 191  * \param[in]  op     Operation to clear if rsc is specified (or NULL for all)
 192  * \param[in]  interval_ms  Interval of operation to clear if op is specified
 193  *
 194  * \return pcmk_ok on success, -EINVAL if arguments are invalid
 195  *
 196  * \note The caller is responsible for freeing the result with regfree().
 197  */
 198 int
 199 attrd_failure_regex(regex_t *regex, const char *rsc, const char *op,
     /* [previous][next][first][last][top][bottom][index][help] */
 200                     guint interval_ms)
 201 {
 202     char *pattern = NULL;
 203     int rc;
 204 
 205     /* Create a pattern that matches desired attributes */
 206 
 207     if (rsc == NULL) {
 208         pattern = pcmk__str_copy(ATTRD_RE_CLEAR_ALL);
 209     } else if (op == NULL) {
 210         pattern = crm_strdup_printf(ATTRD_RE_CLEAR_ONE, rsc);
 211     } else {
 212         pattern = crm_strdup_printf(ATTRD_RE_CLEAR_OP, rsc, op, interval_ms);
 213     }
 214 
 215     /* Compile pattern into regular expression */
 216     crm_trace("Clearing attributes matching %s", pattern);
 217     rc = regcomp(regex, pattern, REG_EXTENDED|REG_NOSUB);
 218     free(pattern);
 219 
 220     return (rc == 0)? pcmk_ok : -EINVAL;
 221 }
 222 
 223 void
 224 attrd_free_attribute_value(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 225 {
 226     attribute_value_t *v = data;
 227 
 228     free(v->nodename);
 229     free(v->current);
 230     free(v->requested);
 231     free(v);
 232 }
 233 
 234 void
 235 attrd_free_attribute(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 236 {
 237     attribute_t *a = data;
 238     if(a) {
 239         free(a->id);
 240         free(a->set_id);
 241         free(a->set_type);
 242         free(a->user);
 243 
 244         mainloop_timer_del(a->timer);
 245         g_hash_table_destroy(a->values);
 246 
 247         free(a);
 248     }
 249 }
 250 
 251 /*!
 252  * \internal
 253  * \brief When a peer node leaves the cluster, stop tracking its protocol version.
 254  *
 255  * \param[in] host  The peer node's uname to be removed
 256  */
 257 void
 258 attrd_remove_peer_protocol_ver(const char *host)
     /* [previous][next][first][last][top][bottom][index][help] */
 259 {
 260     if (peer_protocol_vers != NULL) {
 261         g_hash_table_remove(peer_protocol_vers, host);
 262     }
 263 }
 264 
 265 /*!
 266  * \internal
 267  * \brief When a peer node broadcasts a message with its protocol version, keep
 268  *        track of that information.
 269  *
 270  * We keep track of each peer's protocol version so we know which peers to
 271  * expect confirmation messages from when handling cluster-wide sync points.
 272  * We additionally keep track of the lowest protocol version supported by all
 273  * peers so we know when we can send IPC messages containing more than one
 274  * request.
 275  *
 276  * \param[in] host  The peer node's uname to be tracked
 277  * \param[in] value The peer node's protocol version
 278  */
 279 void
 280 attrd_update_minimum_protocol_ver(const char *host, const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 281 {
 282     int ver;
 283 
 284     if (peer_protocol_vers == NULL) {
 285         peer_protocol_vers = pcmk__strkey_table(free, NULL);
 286     }
 287 
 288     pcmk__scan_min_int(value, &ver, 0);
 289 
 290     if (ver > 0) {
 291         /* Record the peer attrd's protocol version. */
 292         g_hash_table_insert(peer_protocol_vers, pcmk__str_copy(host),
 293                             GINT_TO_POINTER(ver));
 294 
 295         /* If the protocol version is a new minimum, record it as such. */
 296         if (minimum_protocol_version == -1 || ver < minimum_protocol_version) {
 297             minimum_protocol_version = ver;
 298             crm_trace("Set minimum attrd protocol version to %d",
 299                       minimum_protocol_version);
 300         }
 301     }
 302 }

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