summaryrefslogtreecommitdiffstats
path: root/lib/pengine/remote.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 06:53:20 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 06:53:20 +0000
commite5a812082ae033afb1eed82c0f2df3d0f6bdc93f (patch)
treea6716c9275b4b413f6c9194798b34b91affb3cc7 /lib/pengine/remote.c
parentInitial commit. (diff)
downloadpacemaker-e5a812082ae033afb1eed82c0f2df3d0f6bdc93f.tar.xz
pacemaker-e5a812082ae033afb1eed82c0f2df3d0f6bdc93f.zip
Adding upstream version 2.1.6.upstream/2.1.6
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib/pengine/remote.c')
-rw-r--r--lib/pengine/remote.c270
1 files changed, 270 insertions, 0 deletions
diff --git a/lib/pengine/remote.c b/lib/pengine/remote.c
new file mode 100644
index 0000000..769635f
--- /dev/null
+++ b/lib/pengine/remote.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2013-2022 the Pacemaker project contributors
+ *
+ * The version control history for this file may have further details.
+ *
+ * This source code is licensed under the GNU Lesser General Public License
+ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
+ */
+
+#include <crm_internal.h>
+#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
+#include <crm/pengine/internal.h>
+#include <glib.h>
+
+bool
+pe__resource_is_remote_conn(const pe_resource_t *rsc,
+ const pe_working_set_t *data_set)
+{
+ return (rsc != NULL) && rsc->is_remote_node
+ && pe__is_remote_node(pe_find_node(data_set->nodes, rsc->id));
+}
+
+bool
+pe__is_remote_node(const pe_node_t *node)
+{
+ return (node != NULL) && (node->details->type == node_remote)
+ && ((node->details->remote_rsc == NULL)
+ || (node->details->remote_rsc->container == NULL));
+}
+
+bool
+pe__is_guest_node(const pe_node_t *node)
+{
+ return (node != NULL) && (node->details->type == node_remote)
+ && (node->details->remote_rsc != NULL)
+ && (node->details->remote_rsc->container != NULL);
+}
+
+bool
+pe__is_guest_or_remote_node(const pe_node_t *node)
+{
+ return (node != NULL) && (node->details->type == node_remote);
+}
+
+bool
+pe__is_bundle_node(const pe_node_t *node)
+{
+ return pe__is_guest_node(node)
+ && pe_rsc_is_bundled(node->details->remote_rsc);
+}
+
+/*!
+ * \internal
+ * \brief Check whether a resource creates a guest node
+ *
+ * If a given resource contains a filler resource that is a remote connection,
+ * return that filler resource (or NULL if none is found).
+ *
+ * \param[in] data_set Working set of cluster
+ * \param[in] rsc Resource to check
+ *
+ * \return Filler resource with remote connection, or NULL if none found
+ */
+pe_resource_t *
+pe__resource_contains_guest_node(const pe_working_set_t *data_set,
+ const pe_resource_t *rsc)
+{
+ if ((rsc != NULL) && (data_set != NULL)
+ && pcmk_is_set(data_set->flags, pe_flag_have_remote_nodes)) {
+
+ for (GList *gIter = rsc->fillers; gIter != NULL; gIter = gIter->next) {
+ pe_resource_t *filler = gIter->data;
+
+ if (filler->is_remote_node) {
+ return filler;
+ }
+ }
+ }
+ return NULL;
+}
+
+bool
+xml_contains_remote_node(xmlNode *xml)
+{
+ const char *value = NULL;
+
+ if (xml == NULL) {
+ return false;
+ }
+
+ value = crm_element_value(xml, XML_ATTR_TYPE);
+ if (!pcmk__str_eq(value, "remote", pcmk__str_casei)) {
+ return false;
+ }
+
+ value = crm_element_value(xml, XML_AGENT_ATTR_CLASS);
+ if (!pcmk__str_eq(value, PCMK_RESOURCE_CLASS_OCF, pcmk__str_casei)) {
+ return false;
+ }
+
+ value = crm_element_value(xml, XML_AGENT_ATTR_PROVIDER);
+ if (!pcmk__str_eq(value, "pacemaker", pcmk__str_casei)) {
+ return false;
+ }
+
+ return true;
+}
+
+/*!
+ * \internal
+ * \brief Execute a supplied function for each guest node running on a host
+ *
+ * \param[in] data_set Working set for cluster
+ * \param[in] host Host node to check
+ * \param[in] helper Function to call for each guest node
+ * \param[in,out] user_data Pointer to pass to helper function
+ */
+void
+pe_foreach_guest_node(const pe_working_set_t *data_set, const pe_node_t *host,
+ void (*helper)(const pe_node_t*, void*), void *user_data)
+{
+ GList *iter;
+
+ CRM_CHECK(data_set && host && host->details && helper, return);
+ if (!pcmk_is_set(data_set->flags, pe_flag_have_remote_nodes)) {
+ return;
+ }
+ for (iter = host->details->running_rsc; iter != NULL; iter = iter->next) {
+ pe_resource_t *rsc = (pe_resource_t *) iter->data;
+
+ if (rsc->is_remote_node && (rsc->container != NULL)) {
+ pe_node_t *guest_node = pe_find_node(data_set->nodes, rsc->id);
+
+ if (guest_node) {
+ (*helper)(guest_node, user_data);
+ }
+ }
+ }
+}
+
+/*!
+ * \internal
+ * \brief Create CIB XML for an implicit remote connection
+ *
+ * \param[in,out] parent If not NULL, use as parent XML element
+ * \param[in] uname Name of Pacemaker Remote node
+ * \param[in] container If not NULL, use this as connection container
+ * \param[in] migrateable If not NULL, use as allow-migrate value
+ * \param[in] is_managed If not NULL, use as is-managed value
+ * \param[in] start_timeout If not NULL, use as remote connect timeout
+ * \param[in] server If not NULL, use as remote server value
+ * \param[in] port If not NULL, use as remote port value
+ *
+ * \return Newly created XML
+ */
+xmlNode *
+pe_create_remote_xml(xmlNode *parent, const char *uname,
+ const char *container_id, const char *migrateable,
+ const char *is_managed, const char *start_timeout,
+ const char *server, const char *port)
+{
+ xmlNode *remote;
+ xmlNode *xml_sub;
+
+ remote = create_xml_node(parent, XML_CIB_TAG_RESOURCE);
+
+ // Add identity
+ crm_xml_add(remote, XML_ATTR_ID, uname);
+ crm_xml_add(remote, XML_AGENT_ATTR_CLASS, PCMK_RESOURCE_CLASS_OCF);
+ crm_xml_add(remote, XML_AGENT_ATTR_PROVIDER, "pacemaker");
+ crm_xml_add(remote, XML_ATTR_TYPE, "remote");
+
+ // Add meta-attributes
+ xml_sub = create_xml_node(remote, XML_TAG_META_SETS);
+ crm_xml_set_id(xml_sub, "%s-%s", uname, XML_TAG_META_SETS);
+ crm_create_nvpair_xml(xml_sub, NULL,
+ XML_RSC_ATTR_INTERNAL_RSC, XML_BOOLEAN_TRUE);
+ if (container_id) {
+ crm_create_nvpair_xml(xml_sub, NULL,
+ XML_RSC_ATTR_CONTAINER, container_id);
+ }
+ if (migrateable) {
+ crm_create_nvpair_xml(xml_sub, NULL,
+ XML_OP_ATTR_ALLOW_MIGRATE, migrateable);
+ }
+ if (is_managed) {
+ crm_create_nvpair_xml(xml_sub, NULL, XML_RSC_ATTR_MANAGED, is_managed);
+ }
+
+ // Add instance attributes
+ if (port || server) {
+ xml_sub = create_xml_node(remote, XML_TAG_ATTR_SETS);
+ crm_xml_set_id(xml_sub, "%s-%s", uname, XML_TAG_ATTR_SETS);
+ if (server) {
+ crm_create_nvpair_xml(xml_sub, NULL, XML_RSC_ATTR_REMOTE_RA_ADDR,
+ server);
+ }
+ if (port) {
+ crm_create_nvpair_xml(xml_sub, NULL, "port", port);
+ }
+ }
+
+ // Add operations
+ xml_sub = create_xml_node(remote, "operations");
+ crm_create_op_xml(xml_sub, uname, "monitor", "30s", "30s");
+ if (start_timeout) {
+ crm_create_op_xml(xml_sub, uname, "start", "0", start_timeout);
+ }
+ return remote;
+}
+
+// History entry to be checked for fail count clearing
+struct check_op {
+ const xmlNode *rsc_op; // History entry XML
+ pe_resource_t *rsc; // Known resource corresponding to history entry
+ pe_node_t *node; // Known node corresponding to history entry
+ enum pe_check_parameters check_type; // What needs checking
+};
+
+void
+pe__add_param_check(const xmlNode *rsc_op, pe_resource_t *rsc,
+ pe_node_t *node, enum pe_check_parameters flag,
+ pe_working_set_t *data_set)
+{
+ struct check_op *check_op = NULL;
+
+ CRM_CHECK(data_set && rsc_op && rsc && node, return);
+
+ check_op = calloc(1, sizeof(struct check_op));
+ CRM_ASSERT(check_op != NULL);
+
+ crm_trace("Deferring checks of %s until after allocation", ID(rsc_op));
+ check_op->rsc_op = rsc_op;
+ check_op->rsc = rsc;
+ check_op->node = node;
+ check_op->check_type = flag;
+ data_set->param_check = g_list_prepend(data_set->param_check, check_op);
+}
+
+/*!
+ * \internal
+ * \brief Call a function for each action to be checked for addr substitution
+ *
+ * \param[in,out] data_set Working set for cluster
+ * \param[in] cb Function to be called
+ */
+void
+pe__foreach_param_check(pe_working_set_t *data_set,
+ void (*cb)(pe_resource_t*, pe_node_t*, const xmlNode*,
+ enum pe_check_parameters))
+{
+ CRM_CHECK(data_set && cb, return);
+
+ for (GList *item = data_set->param_check; item != NULL; item = item->next) {
+ struct check_op *check_op = item->data;
+
+ cb(check_op->rsc, check_op->node, check_op->rsc_op,
+ check_op->check_type);
+ }
+}
+
+void
+pe__free_param_checks(pe_working_set_t *data_set)
+{
+ if (data_set && data_set->param_check) {
+ g_list_free_full(data_set->param_check, free);
+ data_set->param_check = NULL;
+ }
+}