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; request = pcmk__xe_next_same(request)) {
  62 
  63         const char *op = crm_element_value(request, PCMK__XA_CIB_OP);
  64         const char *host = crm_element_value(request, PCMK__XA_CIB_HOST);
  65         const cib__operation_t *operation = NULL;
  66         int rc = cib__get_operation(op, &operation);
  67 
  68         if (rc == pcmk_rc_ok) {
  69             if (!pcmk_is_set(operation->flags, cib__op_attr_transaction)
  70                 || (host != NULL)) {
  71 
  72                 rc = EOPNOTSUPP;
  73             } else {
  74                 /* Commit-transaction is a privileged operation. If we reached
  75                  * this point, the request came from a privileged connection.
  76                  */
  77                 rc = cib_process_request(request, TRUE, client);
  78                 rc = pcmk_legacy2rc(rc);
  79             }
  80         }
  81 
  82         if (rc != pcmk_rc_ok) {
  83             crm_err("Aborting CIB transaction for %s due to failed %s request: "
  84                     "%s",
  85                     source, op, pcmk_rc_str(rc));
  86             crm_log_xml_info(request, "Failed request");
  87             return rc;
  88         }
  89 
  90         crm_trace("Applied %s request to transaction working CIB for %s",
  91                   op, source);
  92         crm_log_xml_trace(request, "Successful request");
  93     }
  94 
  95     return pcmk_rc_ok;
  96 }
  97 
  98 /*!
  99  * \internal
 100  * \brief Commit a given CIB client's transaction to a working CIB copy
 101  *
 102  * \param[in]     transaction  Transaction to commit
 103  * \param[in]     client       CIB client
 104  * \param[in]     origin       Host where the commit request originated
 105  * \param[in,out] result_cib   Where to store result CIB
 106  *
 107  * \return Standard Pacemaker return code
 108  *
 109  * \note This function is expected to be called only by
 110  *       \p cib_process_commit_transaction().
 111  * \note \p result_cib is expected to be a copy of the current CIB as created by
 112  *       \p cib_perform_op().
 113  * \note The caller is responsible for activating and syncing \p result_cib on
 114  *       success, and for freeing it on failure.
 115  */
 116 int
 117 based_commit_transaction(xmlNodePtr transaction, const pcmk__client_t *client,
     /* [previous][next][first][last][top][bottom][index][help] */
 118                          const char *origin, xmlNodePtr *result_cib)
 119 {
 120     xmlNodePtr saved_cib = the_cib;
 121     int rc = pcmk_rc_ok;
 122     char *source = NULL;
 123 
 124     pcmk__assert(result_cib != NULL);
 125 
 126     CRM_CHECK(pcmk__xe_is(transaction, PCMK__XE_CIB_TRANSACTION),
 127               return pcmk_rc_no_transaction);
 128 
 129     /* *result_cib should be a copy of the_cib (created by cib_perform_op()). If
 130      * not, make a copy now. Change tracking isn't strictly required here
 131      * because:
 132      * * Each request in the transaction will have changes tracked and ACLs
 133      *   checked if appropriate.
 134      * * cib_perform_op() will infer changes for the commit request at the end.
 135      */
 136     CRM_CHECK((*result_cib != NULL) && (*result_cib != the_cib),
 137               *result_cib = pcmk__xml_copy(NULL, the_cib));
 138 
 139     source = based_transaction_source_str(client, origin);
 140     crm_trace("Committing transaction for %s to working CIB", source);
 141 
 142     // Apply all changes to a working copy of the CIB
 143     the_cib = *result_cib;
 144 
 145     rc = process_transaction_requests(transaction, client, origin);
 146 
 147     crm_trace("Transaction commit %s for %s",
 148               ((rc == pcmk_rc_ok)? "succeeded" : "failed"), source);
 149 
 150     /* Some request types (for example, erase) may have freed the_cib (the
 151      * working copy) and pointed it at a new XML object. In that case, it
 152      * follows that *result_cib (the working copy) was freed.
 153      *
 154      * Point *result_cib at the updated working copy stored in the_cib.
 155      */
 156     *result_cib = the_cib;
 157 
 158     // Point the_cib back to the unchanged original copy
 159     the_cib = saved_cib;
 160 
 161     free(source);
 162     return rc;
 163 }

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