Line data Source code
1 : /*
2 : * Copyright 2013-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 Lesser General Public License
7 : * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 : */
9 :
10 : #include <crm_internal.h>
11 : #include <crm/common/xml.h>
12 : #include <crm/common/scheduler_internal.h>
13 : #include <crm/pengine/internal.h>
14 : #include <glib.h>
15 :
16 : /*!
17 : * \internal
18 : * \brief Check whether a resource creates a guest node
19 : *
20 : * If a given resource contains a filler resource that is a remote connection,
21 : * return that filler resource (or NULL if none is found).
22 : *
23 : * \param[in] scheduler Scheduler data
24 : * \param[in] rsc Resource to check
25 : *
26 : * \return Filler resource with remote connection, or NULL if none found
27 : */
28 : pcmk_resource_t *
29 0 : pe__resource_contains_guest_node(const pcmk_scheduler_t *scheduler,
30 : const pcmk_resource_t *rsc)
31 : {
32 0 : if ((rsc != NULL) && (scheduler != NULL)
33 0 : && pcmk_is_set(scheduler->flags, pcmk_sched_have_remote_nodes)) {
34 :
35 0 : for (GList *gIter = rsc->fillers; gIter != NULL; gIter = gIter->next) {
36 0 : pcmk_resource_t *filler = gIter->data;
37 :
38 0 : if (filler->is_remote_node) {
39 0 : return filler;
40 : }
41 : }
42 : }
43 0 : return NULL;
44 : }
45 :
46 : bool
47 0 : xml_contains_remote_node(xmlNode *xml)
48 : {
49 0 : const char *value = NULL;
50 :
51 0 : if (xml == NULL) {
52 0 : return false;
53 : }
54 :
55 0 : value = crm_element_value(xml, PCMK_XA_TYPE);
56 0 : if (!pcmk__str_eq(value, "remote", pcmk__str_casei)) {
57 0 : return false;
58 : }
59 :
60 0 : value = crm_element_value(xml, PCMK_XA_CLASS);
61 0 : if (!pcmk__str_eq(value, PCMK_RESOURCE_CLASS_OCF, pcmk__str_casei)) {
62 0 : return false;
63 : }
64 :
65 0 : value = crm_element_value(xml, PCMK_XA_PROVIDER);
66 0 : if (!pcmk__str_eq(value, "pacemaker", pcmk__str_casei)) {
67 0 : return false;
68 : }
69 :
70 0 : return true;
71 : }
72 :
73 : /*!
74 : * \internal
75 : * \brief Execute a supplied function for each guest node running on a host
76 : *
77 : * \param[in] scheduler Scheduler data
78 : * \param[in] host Host node to check
79 : * \param[in] helper Function to call for each guest node
80 : * \param[in,out] user_data Pointer to pass to helper function
81 : */
82 : void
83 0 : pe_foreach_guest_node(const pcmk_scheduler_t *scheduler,
84 : const pcmk_node_t *host,
85 : void (*helper)(const pcmk_node_t*, void*),
86 : void *user_data)
87 : {
88 : GList *iter;
89 :
90 0 : CRM_CHECK(scheduler && host && host->details && helper, return);
91 0 : if (!pcmk_is_set(scheduler->flags, pcmk_sched_have_remote_nodes)) {
92 0 : return;
93 : }
94 0 : for (iter = host->details->running_rsc; iter != NULL; iter = iter->next) {
95 0 : pcmk_resource_t *rsc = (pcmk_resource_t *) iter->data;
96 :
97 0 : if (rsc->is_remote_node && (rsc->container != NULL)) {
98 0 : pcmk_node_t *guest_node = pcmk_find_node(scheduler, rsc->id);
99 :
100 0 : if (guest_node) {
101 0 : (*helper)(guest_node, user_data);
102 : }
103 : }
104 : }
105 : }
106 :
107 : /*!
108 : * \internal
109 : * \brief Create CIB XML for an implicit remote connection
110 : *
111 : * \param[in,out] parent If not \c NULL, use as parent XML element
112 : * \param[in] uname Name of Pacemaker Remote node
113 : * \param[in] container_id If not \c NULL, use this as connection container
114 : * \param[in] migrateable If not \c NULL, use as remote
115 : * \c PCMK_META_ALLOW_MIGRATE value
116 : * \param[in] is_managed If not \c NULL, use as remote
117 : * \c PCMK_META_IS_MANAGED value
118 : * \param[in] start_timeout If not \c NULL, use as remote connect timeout
119 : * \param[in] server If not \c NULL, use as \c PCMK_REMOTE_RA_ADDR
120 : * \param[in] port If not \c NULL, use as \c PCMK_REMOTE_RA_PORT
121 : *
122 : * \return Newly created XML
123 : */
124 : xmlNode *
125 0 : pe_create_remote_xml(xmlNode *parent, const char *uname,
126 : const char *container_id, const char *migrateable,
127 : const char *is_managed, const char *start_timeout,
128 : const char *server, const char *port)
129 : {
130 : xmlNode *remote;
131 : xmlNode *xml_sub;
132 :
133 0 : remote = pcmk__xe_create(parent, PCMK_XE_PRIMITIVE);
134 :
135 : // Add identity
136 0 : crm_xml_add(remote, PCMK_XA_ID, uname);
137 0 : crm_xml_add(remote, PCMK_XA_CLASS, PCMK_RESOURCE_CLASS_OCF);
138 0 : crm_xml_add(remote, PCMK_XA_PROVIDER, "pacemaker");
139 0 : crm_xml_add(remote, PCMK_XA_TYPE, "remote");
140 :
141 : // Add meta-attributes
142 0 : xml_sub = pcmk__xe_create(remote, PCMK_XE_META_ATTRIBUTES);
143 0 : crm_xml_set_id(xml_sub, "%s-%s", uname, PCMK_XE_META_ATTRIBUTES);
144 0 : crm_create_nvpair_xml(xml_sub, NULL,
145 : PCMK__META_INTERNAL_RSC, PCMK_VALUE_TRUE);
146 0 : if (container_id) {
147 0 : crm_create_nvpair_xml(xml_sub, NULL,
148 : PCMK__META_CONTAINER, container_id);
149 : }
150 0 : if (migrateable) {
151 0 : crm_create_nvpair_xml(xml_sub, NULL,
152 : PCMK_META_ALLOW_MIGRATE, migrateable);
153 : }
154 0 : if (is_managed) {
155 0 : crm_create_nvpair_xml(xml_sub, NULL, PCMK_META_IS_MANAGED, is_managed);
156 : }
157 :
158 : // Add instance attributes
159 0 : if (port || server) {
160 0 : xml_sub = pcmk__xe_create(remote, PCMK_XE_INSTANCE_ATTRIBUTES);
161 0 : crm_xml_set_id(xml_sub, "%s-%s", uname, PCMK_XE_INSTANCE_ATTRIBUTES);
162 0 : if (server) {
163 0 : crm_create_nvpair_xml(xml_sub, NULL, PCMK_REMOTE_RA_ADDR, server);
164 : }
165 0 : if (port) {
166 0 : crm_create_nvpair_xml(xml_sub, NULL, PCMK_REMOTE_RA_PORT, port);
167 : }
168 : }
169 :
170 : // Add operations
171 0 : xml_sub = pcmk__xe_create(remote, PCMK_XE_OPERATIONS);
172 0 : crm_create_op_xml(xml_sub, uname, PCMK_ACTION_MONITOR, "30s", "30s");
173 0 : if (start_timeout) {
174 0 : crm_create_op_xml(xml_sub, uname, PCMK_ACTION_START, "0",
175 : start_timeout);
176 : }
177 0 : return remote;
178 : }
179 :
180 : // History entry to be checked for fail count clearing
181 : struct check_op {
182 : const xmlNode *rsc_op; // History entry XML
183 : pcmk_resource_t *rsc; // Known resource corresponding to history entry
184 : pcmk_node_t *node; // Known node corresponding to history entry
185 : enum pcmk__check_parameters check_type; // What needs checking
186 : };
187 :
188 : void
189 0 : pe__add_param_check(const xmlNode *rsc_op, pcmk_resource_t *rsc,
190 : pcmk_node_t *node, enum pcmk__check_parameters flag,
191 : pcmk_scheduler_t *scheduler)
192 : {
193 0 : struct check_op *check_op = NULL;
194 :
195 0 : CRM_CHECK(scheduler && rsc_op && rsc && node, return);
196 :
197 0 : check_op = pcmk__assert_alloc(1, sizeof(struct check_op));
198 :
199 0 : crm_trace("Deferring checks of %s until after allocation",
200 : pcmk__xe_id(rsc_op));
201 0 : check_op->rsc_op = rsc_op;
202 0 : check_op->rsc = rsc;
203 0 : check_op->node = node;
204 0 : check_op->check_type = flag;
205 0 : scheduler->param_check = g_list_prepend(scheduler->param_check, check_op);
206 : }
207 :
208 : /*!
209 : * \internal
210 : * \brief Call a function for each action to be checked for addr substitution
211 : *
212 : * \param[in,out] scheduler Scheduler data
213 : * \param[in] cb Function to be called
214 : */
215 : void
216 0 : pe__foreach_param_check(pcmk_scheduler_t *scheduler,
217 : void (*cb)(pcmk_resource_t*, pcmk_node_t*,
218 : const xmlNode*, enum pcmk__check_parameters))
219 : {
220 0 : CRM_CHECK(scheduler && cb, return);
221 :
222 0 : for (GList *item = scheduler->param_check;
223 0 : item != NULL; item = item->next) {
224 0 : struct check_op *check_op = item->data;
225 :
226 0 : cb(check_op->rsc, check_op->node, check_op->rsc_op,
227 : check_op->check_type);
228 : }
229 : }
230 :
231 : void
232 0 : pe__free_param_checks(pcmk_scheduler_t *scheduler)
233 : {
234 0 : if (scheduler && scheduler->param_check) {
235 0 : g_list_free_full(scheduler->param_check, free);
236 0 : scheduler->param_check = NULL;
237 : }
238 0 : }
|