root/daemons/controld/controld_based.c

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

DEFINITIONS

This source file includes following definitions.
  1. do_cib_updated
  2. do_cib_replaced
  3. controld_disconnect_cib_manager
  4. do_cib_control
  5. crmd_cib_smart_opt
  6. controld_action_is_recordable
  7. cib_delete_callback
  8. controld_delete_node_state
  9. controld_delete_resource_history

   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 
  12 #include <unistd.h>  /* sleep */
  13 
  14 #include <crm/common/alerts_internal.h>
  15 #include <crm/common/xml.h>
  16 #include <crm/crm.h>
  17 #include <crm/msg_xml.h>
  18 
  19 #include <pacemaker-controld.h>
  20 
  21 int cib_retries = 0;
  22 
  23 void
  24 do_cib_updated(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
  25 {
  26     if (pcmk__alert_in_patchset(msg, TRUE)) {
  27         mainloop_set_trigger(config_read);
  28     }
  29 }
  30 
  31 void
  32 do_cib_replaced(const char *event, xmlNode * msg)
     /* [previous][next][first][last][top][bottom][index][help] */
  33 {
  34     uint32_t change_section = cib_change_section_nodes
  35                               |cib_change_section_status;
  36     long long value = 0;
  37 
  38     crm_debug("Updating the CIB after a replace: DC=%s", pcmk__btoa(AM_I_DC));
  39     if (AM_I_DC == FALSE) {
  40         return;
  41 
  42     } else if ((fsa_state == S_FINALIZE_JOIN)
  43                && pcmk_is_set(fsa_input_register, R_CIB_ASKED)) {
  44         /* no need to restart the join - we asked for this replace op */
  45         return;
  46     }
  47 
  48     if ((crm_element_value_ll(msg, F_CIB_CHANGE_SECTION, &value) < 0)
  49         || (value < 0) || (value > UINT32_MAX)) {
  50 
  51         crm_trace("Couldn't parse '%s' from message", F_CIB_CHANGE_SECTION);
  52     } else {
  53         change_section = (uint32_t) value;
  54     }
  55 
  56     if (pcmk_any_flags_set(change_section, cib_change_section_nodes
  57                                            |cib_change_section_status)) {
  58 
  59         /* start the join process again so we get everyone's LRM status */
  60         populate_cib_nodes(node_update_quick|node_update_all, __func__);
  61 
  62         register_fsa_input(C_FSA_INTERNAL, I_ELECTION, NULL);
  63     }
  64 }
  65 
  66 void
  67 controld_disconnect_cib_manager(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69     CRM_ASSERT(fsa_cib_conn != NULL);
  70 
  71     crm_info("Disconnecting from the CIB manager");
  72 
  73     controld_clear_fsa_input_flags(R_CIB_CONNECTED);
  74 
  75     fsa_cib_conn->cmds->del_notify_callback(fsa_cib_conn, T_CIB_REPLACE_NOTIFY, do_cib_replaced);
  76     fsa_cib_conn->cmds->del_notify_callback(fsa_cib_conn, T_CIB_DIFF_NOTIFY, do_cib_updated);
  77     cib_free_callbacks(fsa_cib_conn);
  78     if (fsa_cib_conn->state != cib_disconnected) {
  79         fsa_cib_conn->cmds->set_secondary(fsa_cib_conn,
  80                                           cib_scope_local|cib_discard_reply);
  81         fsa_cib_conn->cmds->signoff(fsa_cib_conn);
  82     }
  83 
  84     crm_notice("Disconnected from the CIB manager");
  85 }
  86 
  87 /* A_CIB_STOP, A_CIB_START, O_CIB_RESTART */
  88 void
  89 do_cib_control(long long action,
     /* [previous][next][first][last][top][bottom][index][help] */
  90                enum crmd_fsa_cause cause,
  91                enum crmd_fsa_state cur_state,
  92                enum crmd_fsa_input current_input, fsa_data_t * msg_data)
  93 {
  94     CRM_ASSERT(fsa_cib_conn != NULL);
  95 
  96     if (action & A_CIB_STOP) {
  97 
  98         if (fsa_cib_conn->state != cib_disconnected && last_resource_update != 0) {
  99             crm_info("Waiting for resource update %d to complete", last_resource_update);
 100             crmd_fsa_stall(FALSE);
 101             return;
 102         }
 103 
 104         controld_disconnect_cib_manager();
 105 
 106     }
 107 
 108     if (action & A_CIB_START) {
 109         int rc = pcmk_ok;
 110 
 111         if (cur_state == S_STOPPING) {
 112             crm_err("Ignoring request to connect to the CIB manager after shutdown");
 113             return;
 114         }
 115 
 116         rc = fsa_cib_conn->cmds->signon(fsa_cib_conn, CRM_SYSTEM_CRMD, cib_command_nonblocking);
 117 
 118         if (rc != pcmk_ok) {
 119             /* a short wait that usually avoids stalling the FSA */
 120             sleep(1);
 121             rc = fsa_cib_conn->cmds->signon(fsa_cib_conn, CRM_SYSTEM_CRMD, cib_command_nonblocking);
 122         }
 123 
 124         if (rc != pcmk_ok) {
 125             crm_info("Could not connect to the CIB manager: %s", pcmk_strerror(rc));
 126 
 127         } else if (pcmk_ok !=
 128                    fsa_cib_conn->cmds->set_connection_dnotify(fsa_cib_conn,
 129                                                               crmd_cib_connection_destroy)) {
 130             crm_err("Could not set dnotify callback");
 131 
 132         } else if (pcmk_ok !=
 133                    fsa_cib_conn->cmds->add_notify_callback(fsa_cib_conn, T_CIB_REPLACE_NOTIFY,
 134                                                            do_cib_replaced)) {
 135             crm_err("Could not set CIB notification callback (replace)");
 136 
 137         } else if (pcmk_ok !=
 138                    fsa_cib_conn->cmds->add_notify_callback(fsa_cib_conn, T_CIB_DIFF_NOTIFY,
 139                                                            do_cib_updated)) {
 140             crm_err("Could not set CIB notification callback (update)");
 141 
 142         } else {
 143             controld_set_fsa_input_flags(R_CIB_CONNECTED);
 144             cib_retries = 0;
 145         }
 146 
 147         if (!pcmk_is_set(fsa_input_register, R_CIB_CONNECTED)) {
 148 
 149             cib_retries++;
 150             crm_warn("Couldn't complete CIB registration %d"
 151                      " times... pause and retry", cib_retries);
 152 
 153             if (cib_retries < 30) {
 154                 controld_start_timer(wait_timer);
 155                 crmd_fsa_stall(FALSE);
 156 
 157             } else {
 158                 crm_err("Could not complete CIB"
 159                         " registration  %d times..." " hard error", cib_retries);
 160                 register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
 161             }
 162         }
 163     }
 164 }
 165 
 166 /*!
 167  * \internal
 168  * \brief Get CIB call options to use local scope if primary is unavailable
 169  *
 170  * \return CIB call options
 171  */
 172 int
 173 crmd_cib_smart_opt(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 174 {
 175     int call_opt = cib_quorum_override;
 176 
 177     if (fsa_state == S_ELECTION || fsa_state == S_PENDING) {
 178         crm_info("Sending update to local CIB in state: %s", fsa_state2string(fsa_state));
 179         cib__set_call_options(call_opt, "update", cib_scope_local);
 180     }
 181     return call_opt;
 182 }
 183 
 184 /*!
 185  * \internal
 186  * \brief Check whether an action type should be recorded in the CIB
 187  *
 188  * \param[in] action  Action type
 189  *
 190  * \return TRUE if action should be recorded, FALSE otherwise
 191  */
 192 bool
 193 controld_action_is_recordable(const char *action)
     /* [previous][next][first][last][top][bottom][index][help] */
 194 {
 195     return !pcmk__strcase_any_of(action, CRMD_ACTION_CANCEL, CRMD_ACTION_DELETE,
 196                             CRMD_ACTION_NOTIFY, CRMD_ACTION_METADATA, NULL);
 197 }
 198 
 199 static void
 200 cib_delete_callback(xmlNode *msg, int call_id, int rc, xmlNode *output,
     /* [previous][next][first][last][top][bottom][index][help] */
 201                     void *user_data)
 202 {
 203     char *desc = user_data;
 204 
 205     if (rc == 0) {
 206         crm_debug("Deletion of %s (via CIB call %d) succeeded", desc, call_id);
 207     } else {
 208         crm_warn("Deletion of %s (via CIB call %d) failed: %s " CRM_XS " rc=%d",
 209                  desc, call_id, pcmk_strerror(rc), rc);
 210     }
 211 }
 212 
 213 // Searches for various portions of node_state to delete
 214 
 215 // Match a particular node's node_state (takes node name 1x)
 216 #define XPATH_NODE_STATE        "//" XML_CIB_TAG_STATE "[@" XML_ATTR_UNAME "='%s']"
 217 
 218 // Node's lrm section (name 1x)
 219 #define XPATH_NODE_LRM          XPATH_NODE_STATE "/" XML_CIB_TAG_LRM
 220 
 221 // Node's lrm_rsc_op entries and lrm_resource entries without lock (name 2x)
 222 #define XPATH_NODE_LRM_UNLOCKED XPATH_NODE_STATE "//" XML_LRM_TAG_RSC_OP    \
 223                                 "|" XPATH_NODE_STATE                        \
 224                                 "//" XML_LRM_TAG_RESOURCE                   \
 225                                 "[not(@" XML_CONFIG_ATTR_SHUTDOWN_LOCK ")]"
 226 
 227 // Node's transient_attributes section (name 1x)
 228 #define XPATH_NODE_ATTRS        XPATH_NODE_STATE "/" XML_TAG_TRANSIENT_NODEATTRS
 229 
 230 // Everything under node_state (name 1x)
 231 #define XPATH_NODE_ALL          XPATH_NODE_STATE "/*"
 232 
 233 // Unlocked history + transient attributes (name 3x)
 234 #define XPATH_NODE_ALL_UNLOCKED XPATH_NODE_LRM_UNLOCKED "|" XPATH_NODE_ATTRS
 235 
 236 /*!
 237  * \internal
 238  * \brief Delete subsection of a node's CIB node_state
 239  *
 240  * \param[in] uname    Desired node
 241  * \param[in] section  Subsection of node_state to delete
 242  * \param[in] options  CIB call options to use
 243  */
 244 void
 245 controld_delete_node_state(const char *uname, enum controld_section_e section,
     /* [previous][next][first][last][top][bottom][index][help] */
 246                            int options)
 247 {
 248     char *xpath = NULL;
 249     char *desc = NULL;
 250 
 251     CRM_CHECK(uname != NULL, return);
 252     switch (section) {
 253         case controld_section_lrm:
 254             xpath = crm_strdup_printf(XPATH_NODE_LRM, uname);
 255             desc = crm_strdup_printf("resource history for node %s", uname);
 256             break;
 257         case controld_section_lrm_unlocked:
 258             xpath = crm_strdup_printf(XPATH_NODE_LRM_UNLOCKED, uname, uname);
 259             desc = crm_strdup_printf("resource history (other than shutdown "
 260                                      "locks) for node %s", uname);
 261             break;
 262         case controld_section_attrs:
 263             xpath = crm_strdup_printf(XPATH_NODE_ATTRS, uname);
 264             desc = crm_strdup_printf("transient attributes for node %s", uname);
 265             break;
 266         case controld_section_all:
 267             xpath = crm_strdup_printf(XPATH_NODE_ALL, uname);
 268             desc = crm_strdup_printf("all state for node %s", uname);
 269             break;
 270         case controld_section_all_unlocked:
 271             xpath = crm_strdup_printf(XPATH_NODE_ALL_UNLOCKED,
 272                                       uname, uname, uname);
 273             desc = crm_strdup_printf("all state (other than shutdown locks) "
 274                                      "for node %s", uname);
 275             break;
 276     }
 277 
 278     if (fsa_cib_conn == NULL) {
 279         crm_warn("Unable to delete %s: no CIB connection", desc);
 280         free(desc);
 281     } else {
 282         int call_id;
 283 
 284         cib__set_call_options(options, "node state deletion",
 285                               cib_quorum_override|cib_xpath|cib_multiple);
 286         call_id = fsa_cib_conn->cmds->remove(fsa_cib_conn, xpath, NULL, options);
 287         crm_info("Deleting %s (via CIB call %d) " CRM_XS " xpath=%s",
 288                  desc, call_id, xpath);
 289         fsa_register_cib_callback(call_id, FALSE, desc, cib_delete_callback);
 290         // CIB library handles freeing desc
 291     }
 292     free(xpath);
 293 }
 294 
 295 // Takes node name and resource ID
 296 #define XPATH_RESOURCE_HISTORY "//" XML_CIB_TAG_STATE                       \
 297                                "[@" XML_ATTR_UNAME "='%s']/"                \
 298                                XML_CIB_TAG_LRM "/" XML_LRM_TAG_RESOURCES    \
 299                                "/" XML_LRM_TAG_RESOURCE                     \
 300                                "[@" XML_ATTR_ID "='%s']"
 301 // @TODO could add "and @XML_CONFIG_ATTR_SHUTDOWN_LOCK" to limit to locks
 302 
 303 /*!
 304  * \internal
 305  * \brief Clear resource history from CIB for a given resource and node
 306  *
 307  * \param[in]  rsc_id        ID of resource to be cleared
 308  * \param[in]  node          Node whose resource history should be cleared
 309  * \param[in]  user_name     ACL user name to use
 310  * \param[in]  call_options  CIB call options
 311  *
 312  * \return Standard Pacemaker return code
 313  */
 314 int
 315 controld_delete_resource_history(const char *rsc_id, const char *node,
     /* [previous][next][first][last][top][bottom][index][help] */
 316                                  const char *user_name, int call_options)
 317 {
 318     char *desc = NULL;
 319     char *xpath = NULL;
 320     int rc = pcmk_rc_ok;
 321 
 322     CRM_CHECK((rsc_id != NULL) && (node != NULL), return EINVAL);
 323 
 324     desc = crm_strdup_printf("resource history for %s on %s", rsc_id, node);
 325     if (fsa_cib_conn == NULL) {
 326         crm_err("Unable to clear %s: no CIB connection", desc);
 327         free(desc);
 328         return ENOTCONN;
 329     }
 330 
 331     // Ask CIB to delete the entry
 332     xpath = crm_strdup_printf(XPATH_RESOURCE_HISTORY, node, rsc_id);
 333     rc = cib_internal_op(fsa_cib_conn, PCMK__CIB_REQUEST_DELETE, NULL, xpath,
 334                          NULL, NULL, call_options|cib_xpath, user_name);
 335 
 336     if (rc < 0) {
 337         rc = pcmk_legacy2rc(rc);
 338         crm_err("Could not delete resource status of %s on %s%s%s: %s "
 339                 CRM_XS " rc=%d", rsc_id, node,
 340                 (user_name? " for user " : ""), (user_name? user_name : ""),
 341                 pcmk_rc_str(rc), rc);
 342         free(desc);
 343         free(xpath);
 344         return rc;
 345     }
 346 
 347     if (pcmk_is_set(call_options, cib_sync_call)) {
 348         if (pcmk_is_set(call_options, cib_dryrun)) {
 349             crm_debug("Deletion of %s would succeed", desc);
 350         } else {
 351             crm_debug("Deletion of %s succeeded", desc);
 352         }
 353         free(desc);
 354 
 355     } else {
 356         crm_info("Clearing %s (via CIB call %d) " CRM_XS " xpath=%s",
 357                  desc, rc, xpath);
 358         fsa_register_cib_callback(rc, FALSE, desc, cib_delete_callback);
 359         // CIB library handles freeing desc
 360     }
 361 
 362     free(xpath);
 363     return pcmk_rc_ok;
 364 }

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