root/daemons/based/based_transaction.c

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

DEFINITIONS

This source file includes following definitions.
  1. based_transaction_source_str
  2. process_transaction_requests
  3. based_commit_transaction

   1 /*
   2  * Copyright 2023-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 <glib.h>
  13 #include <libxml/tree.h>
  14 
  15 #include "pacemaker-based.h"
  16 
  17 /*!
  18  * \internal
  19  * \brief Create a string describing the source of a commit-transaction request
  20  *
  21  * \param[in] client  CIB client
  22  * \param[in] origin  Host where the commit request originated
  23  *
  24  * \return String describing the request source
  25  *
  26  * \note The caller is responsible for freeing the return value using \c free().
  27  */
  28 char *
  29 based_transaction_source_str(const pcmk__client_t *client, const char *origin)
     /* [previous][next][first][last][top][bottom][index][help] */
  30 {
  31     if (client != NULL) {
  32         return crm_strdup_printf("client %s (%s)%s%s",
  33                                  pcmk__client_name(client),
  34                                  pcmk__s(client->id, "unidentified"),
  35                                  ((origin != NULL)? " on " : ""),
  36                                  pcmk__s(origin, ""));
  37     } else {
  38         return pcmk__str_copy(pcmk__s(origin, "unknown source"));
  39     }
  40 }
  41 
  42 /*!
  43  * \internal
  44  * \brief Process requests in a transaction
  45  *
  46  * Stop when a request fails or when all requests have been processed.
  47  *
  48  * \param[in,out] transaction  Transaction to process
  49  * \param[in]     client       CIB client
  50  * \param[in]     source       String describing the commit request source
  51  *
  52  * \return Standard Pacemaker return code
  53  */
  54 static int
  55 process_transaction_requests(xmlNodePtr transaction,
     /* [previous][next][first][last][top][bottom][index][help] */
  56                              const pcmk__client_t *client, const char *source)
  57 {
  58     for (xmlNode *request = pcmk__xe_first_child(transaction,
  59                                                  PCMK__XE_CIB_COMMAND, NULL,
  60                                                  NULL);
  61          request != NULL;
  62          request = pcmk__xe_next(request, PCMK__XE_CIB_COMMAND)) {
  63 
  64         const char *op = crm_element_value(request, PCMK__XA_CIB_OP);
  65         const char *host = crm_element_value(request, PCMK__XA_CIB_HOST);
  66         const cib__operation_t *operation = NULL;
  67         int rc = cib__get_operation(op, &operation);
  68 
  69         if (rc == pcmk_rc_ok) {
  70             if (!pcmk_is_set(operation->flags, cib__op_attr_transaction)
  71                 || (host != NULL)) {
  72 
  73                 rc = EOPNOTSUPP;
  74             } else {
  75                 /* Commit-transaction is a privileged operation. If we reached
  76                  * this point, the request came from a privileged connection.
  77                  */
  78                 rc = cib_process_request(request, TRUE, client);
  79                 rc = pcmk_legacy2rc(rc);
  80             }
  81         }
  82 
  83         if (rc != pcmk_rc_ok) {
  84             crm_err("Aborting CIB transaction for %s due to failed %s request: "
  85                     "%s",
  86                     source, op, pcmk_rc_str(rc));
  87             crm_log_xml_info(request, "Failed request");
  88             return rc;
  89         }
  90 
  91         crm_trace("Applied %s request to transaction working CIB for %s",
  92                   op, source);
  93         crm_log_xml_trace(request, "Successful request");
  94     }
  95 
  96     return pcmk_rc_ok;
  97 }
  98 
  99 /*!
 100  * \internal
 101  * \brief Commit a given CIB client's transaction to a working CIB copy
 102  *
 103  * \param[in]     transaction  Transaction to commit
 104  * \param[in]     client       CIB client
 105  * \param[in]     origin       Host where the commit request originated
 106  * \param[in,out] result_cib   Where to store result CIB
 107  *
 108  * \return Standard Pacemaker return code
 109  *
 110  * \note This function is expected to be called only by
 111  *       \p cib_process_commit_transaction().
 112  * \note \p result_cib is expected to be a copy of the current CIB as created by
 113  *       \p cib_perform_op().
 114  * \note The caller is responsible for activating and syncing \p result_cib on
 115  *       success, and for freeing it on failure.
 116  */
 117 int
 118 based_commit_transaction(xmlNodePtr transaction, const pcmk__client_t *client,
     /* [previous][next][first][last][top][bottom][index][help] */
 119                          const char *origin, xmlNodePtr *result_cib)
 120 {
 121     xmlNodePtr saved_cib = the_cib;
 122     int rc = pcmk_rc_ok;
 123     char *source = NULL;
 124 
 125     pcmk__assert(result_cib != NULL);
 126 
 127     CRM_CHECK(pcmk__xe_is(transaction, PCMK__XE_CIB_TRANSACTION),
 128               return pcmk_rc_no_transaction);
 129 
 130     /* *result_cib should be a copy of the_cib (created by cib_perform_op()). If
 131      * not, make a copy now. Change tracking isn't strictly required here
 132      * because:
 133      * * Each request in the transaction will have changes tracked and ACLs
 134      *   checked if appropriate.
 135      * * cib_perform_op() will infer changes for the commit request at the end.
 136      */
 137     CRM_CHECK((*result_cib != NULL) && (*result_cib != the_cib),
 138               *result_cib = pcmk__xml_copy(NULL, the_cib));
 139 
 140     source = based_transaction_source_str(client, origin);
 141     crm_trace("Committing transaction for %s to working CIB", source);
 142 
 143     // Apply all changes to a working copy of the CIB
 144     the_cib = *result_cib;
 145 
 146     rc = process_transaction_requests(transaction, client, origin);
 147 
 148     crm_trace("Transaction commit %s for %s",
 149               ((rc == pcmk_rc_ok)? "succeeded" : "failed"), source);
 150 
 151     /* Some request types (for example, erase) may have freed the_cib (the
 152      * working copy) and pointed it at a new XML object. In that case, it
 153      * follows that *result_cib (the working copy) was freed.
 154      *
 155      * Point *result_cib at the updated working copy stored in the_cib.
 156      */
 157     *result_cib = the_cib;
 158 
 159     // Point the_cib back to the unchanged original copy
 160     the_cib = saved_cib;
 161 
 162     free(source);
 163     return rc;
 164 }

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