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

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