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
  14. attrd_copy_xml_attributes

   1 /*
   2  * Copyright 2004-2023 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/msg_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  Also consider presence of "shutdown" attribute
  62  *
  63  * \return \c true if local attribute manager has begun shutdown sequence
  64  *         or (if \p if_requested is \c true) whether local node has a nonzero
  65  *         "shutdown" attribute set, otherwise \c false
  66  * \note Most callers should pass \c false for \p if_requested, because the
  67  *       attribute manager needs to continue performing while the controller is
  68  *       shutting down, and even needs to be eligible for election in case all
  69  *       nodes are shutting down.
  70  */
  71 bool
  72 attrd_shutting_down(bool if_requested)
     /* [previous][next][first][last][top][bottom][index][help] */
  73 {
  74     return shutting_down || (if_requested && requesting_shutdown);
  75 }
  76 
  77 /*!
  78  * \internal
  79  * \brief  Exit (using mainloop or not, as appropriate)
  80  *
  81  * \param[in] nsig  Ignored
  82  */
  83 void
  84 attrd_shutdown(int nsig)
     /* [previous][next][first][last][top][bottom][index][help] */
  85 {
  86     // Tell various functions not to do anthing
  87     shutting_down = true;
  88 
  89     // Don't respond to signals while shutting down
  90     mainloop_destroy_signal(SIGTERM);
  91     mainloop_destroy_signal(SIGCHLD);
  92     mainloop_destroy_signal(SIGPIPE);
  93     mainloop_destroy_signal(SIGUSR1);
  94     mainloop_destroy_signal(SIGUSR2);
  95     mainloop_destroy_signal(SIGTRAP);
  96 
  97     attrd_free_waitlist();
  98     attrd_free_confirmations();
  99 
 100     if (peer_protocol_vers != NULL) {
 101         g_hash_table_destroy(peer_protocol_vers);
 102         peer_protocol_vers = NULL;
 103     }
 104 
 105     if ((mloop == NULL) || !g_main_loop_is_running(mloop)) {
 106         /* If there's no main loop active, just exit. This should be possible
 107          * only if we get SIGTERM in brief windows at start-up and shutdown.
 108          */
 109         crm_exit(CRM_EX_OK);
 110     } else {
 111         g_main_loop_quit(mloop);
 112         g_main_loop_unref(mloop);
 113     }
 114 }
 115 
 116 /*!
 117  * \internal
 118  * \brief Create a main loop for attrd
 119  */
 120 void
 121 attrd_init_mainloop(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123     mloop = g_main_loop_new(NULL, FALSE);
 124 }
 125 
 126 /*!
 127  * \internal
 128  * \brief Run attrd main loop
 129  */
 130 void
 131 attrd_run_mainloop(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 132 {
 133     g_main_loop_run(mloop);
 134 }
 135 
 136 /* strlen("value") */
 137 #define plus_plus_len (5)
 138 
 139 /*!
 140  * \internal
 141  * \brief  Check whether an attribute value should be expanded
 142  *
 143  * \param[in] value  Attribute value to check
 144  *
 145  * \return true if value needs expansion, false otherwise
 146  */
 147 bool
 148 attrd_value_needs_expansion(const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
 149 {
 150     return ((strlen(value) >= (plus_plus_len + 2))
 151            && (value[plus_plus_len] == '+')
 152            && ((value[plus_plus_len + 1] == '+')
 153                || (value[plus_plus_len + 1] == '=')));
 154 }
 155 
 156 /*!
 157  * \internal
 158  * \brief Expand an increment expression into an integer
 159  *
 160  * \param[in] value      Attribute increment expression to expand
 161  * \param[in] old_value  Previous value of attribute
 162  *
 163  * \return Expanded value
 164  */
 165 int
 166 attrd_expand_value(const char *value, const char *old_value)
     /* [previous][next][first][last][top][bottom][index][help] */
 167 {
 168     int offset = 1;
 169     int int_value = char2score(old_value);
 170 
 171     if (value[plus_plus_len + 1] != '+') {
 172         const char *offset_s = value + (plus_plus_len + 2);
 173 
 174         offset = char2score(offset_s);
 175     }
 176     int_value += offset;
 177 
 178     if (int_value > INFINITY) {
 179         int_value = INFINITY;
 180     }
 181     return int_value;
 182 }
 183 
 184 /*!
 185  * \internal
 186  * \brief Create regular expression matching failure-related attributes
 187  *
 188  * \param[out] regex  Where to store created regular expression
 189  * \param[in]  rsc    Name of resource to clear (or NULL for all)
 190  * \param[in]  op     Operation to clear if rsc is specified (or NULL for all)
 191  * \param[in]  interval_ms  Interval of operation to clear if op is specified
 192  *
 193  * \return pcmk_ok on success, -EINVAL if arguments are invalid
 194  *
 195  * \note The caller is responsible for freeing the result with regfree().
 196  */
 197 int
 198 attrd_failure_regex(regex_t *regex, const char *rsc, const char *op,
     /* [previous][next][first][last][top][bottom][index][help] */
 199                     guint interval_ms)
 200 {
 201     char *pattern = NULL;
 202     int rc;
 203 
 204     /* Create a pattern that matches desired attributes */
 205 
 206     if (rsc == NULL) {
 207         pattern = strdup(ATTRD_RE_CLEAR_ALL);
 208     } else if (op == NULL) {
 209         pattern = crm_strdup_printf(ATTRD_RE_CLEAR_ONE, rsc);
 210     } else {
 211         pattern = crm_strdup_printf(ATTRD_RE_CLEAR_OP, rsc, op, interval_ms);
 212     }
 213 
 214     /* Compile pattern into regular expression */
 215     crm_trace("Clearing attributes matching %s", pattern);
 216     rc = regcomp(regex, pattern, REG_EXTENDED|REG_NOSUB);
 217     free(pattern);
 218 
 219     return (rc == 0)? pcmk_ok : -EINVAL;
 220 }
 221 
 222 void
 223 attrd_free_attribute_value(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 224 {
 225     attribute_value_t *v = data;
 226 
 227     free(v->nodename);
 228     free(v->current);
 229     free(v->requested);
 230     free(v);
 231 }
 232 
 233 void
 234 attrd_free_attribute(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 235 {
 236     attribute_t *a = data;
 237     if(a) {
 238         free(a->id);
 239         free(a->set_id);
 240         free(a->set_type);
 241         free(a->uuid);
 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         char *host_name = strdup(host);
 292 
 293         /* Record the peer attrd's protocol version. */
 294         CRM_ASSERT(host_name != NULL);
 295         g_hash_table_insert(peer_protocol_vers, host_name, GINT_TO_POINTER(ver));
 296 
 297         /* If the protocol version is a new minimum, record it as such. */
 298         if (minimum_protocol_version == -1 || ver < minimum_protocol_version) {
 299             minimum_protocol_version = ver;
 300             crm_trace("Set minimum attrd protocol version to %d",
 301                       minimum_protocol_version);
 302         }
 303     }
 304 }
 305 
 306 void
 307 attrd_copy_xml_attributes(xmlNode *src, xmlNode *dest)
     /* [previous][next][first][last][top][bottom][index][help] */
 308 {
 309     /* Copy attributes from the wrapper parent node into the child node.
 310      * We can't just use copy_in_properties because we want to skip any
 311      * attributes that are already set on the child.  For instance, if
 312      * we were told to use a specific node, there will already be a node
 313      * attribute on the child.  Copying the parent's node attribute over
 314      * could result in the wrong value.
 315      */
 316     for (xmlAttrPtr a = pcmk__xe_first_attr(src); a != NULL; a = a->next) {
 317         const char *p_name = (const char *) a->name;
 318         const char *p_value = ((a == NULL) || (a->children == NULL)) ? NULL :
 319                               (const char *) a->children->content;
 320 
 321         if (crm_element_value(dest, p_name) == NULL) {
 322             crm_xml_add(dest, p_name, p_value);
 323         }
 324     }
 325 }

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