This source file includes following definitions.
- parse_cli_lifetime
- cli_resource_ban
- cli_resource_prefer
- resource_clear_node_in_expr
- resource_clear_node_in_location
- cli_resource_clear
- build_clear_xpath_string
- cli_resource_clear_all_expired
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <libxml/tree.h>
13 #include <libxml/xpath.h>
14
15 #include <crm_resource.h>
16
17 static char *
18 parse_cli_lifetime(pcmk__output_t *out, const char *move_lifetime)
19 {
20 char *later_s = NULL;
21 crm_time_t *now = NULL;
22 crm_time_t *later = NULL;
23 crm_time_t *duration = NULL;
24
25 if (move_lifetime == NULL) {
26 return NULL;
27 }
28
29 duration = crm_time_parse_duration(move_lifetime);
30 if (duration == NULL) {
31 out->err(out, "Invalid duration specified: %s\n"
32 "Please refer to https://en.wikipedia.org/wiki/ISO_8601#Durations "
33 "for examples of valid durations", move_lifetime);
34 return NULL;
35 }
36
37 now = crm_time_new(NULL);
38 later = crm_time_add(now, duration);
39 if (later == NULL) {
40 out->err(out, "Unable to add %s to current time\n"
41 "Please report to " PACKAGE_BUGREPORT " as possible bug",
42 move_lifetime);
43 crm_time_free(now);
44 crm_time_free(duration);
45 return NULL;
46 }
47
48 crm_time_log(LOG_INFO, "now ", now,
49 crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
50 crm_time_log(LOG_INFO, "later ", later,
51 crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
52 crm_time_log(LOG_INFO, "duration", duration, crm_time_log_date | crm_time_log_timeofday);
53 later_s = crm_time_as_string(later, crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
54 out->info(out, "Migration will take effect until: %s", later_s);
55
56 crm_time_free(duration);
57 crm_time_free(later);
58 crm_time_free(now);
59 return later_s;
60 }
61
62
63 int
64 cli_resource_ban(pcmk__output_t *out, const char *rsc_id, const char *host,
65 const char *move_lifetime, cib_t *cib_conn,
66 gboolean promoted_role_only, const char *promoted_role)
67 {
68 char *later_s = NULL;
69 int rc = pcmk_rc_ok;
70 xmlNode *fragment = NULL;
71 xmlNode *location = NULL;
72
73 later_s = parse_cli_lifetime(out, move_lifetime);
74 if(move_lifetime && later_s == NULL) {
75 return EINVAL;
76 }
77
78 fragment = pcmk__xe_create(NULL, PCMK_XE_CONSTRAINTS);
79
80 location = pcmk__xe_create(fragment, PCMK_XE_RSC_LOCATION);
81 pcmk__xe_set_id(location, "cli-ban-%s-on-%s", rsc_id, host);
82
83 out->info(out,
84 "WARNING: Creating " PCMK_XE_RSC_LOCATION " constraint '%s' with "
85 "a score of " PCMK_VALUE_MINUS_INFINITY " for resource %s on %s."
86 "\n\tThis will prevent %s from %s on %s until the constraint is "
87 "removed using the clear option or by editing the CIB with an "
88 "appropriate tool.\n"
89 "\tThis will be the case even if %s is the last node in the "
90 "cluster",
91 pcmk__xe_id(location), rsc_id, host, rsc_id,
92 (promoted_role_only? "being promoted" : "running"), host, host);
93
94 crm_xml_add(location, PCMK_XA_RSC, rsc_id);
95 if(promoted_role_only) {
96 crm_xml_add(location, PCMK_XA_ROLE, promoted_role);
97 } else {
98 crm_xml_add(location, PCMK_XA_ROLE, PCMK_ROLE_STARTED);
99 }
100
101 if (later_s == NULL) {
102
103 crm_xml_add(location, PCMK_XE_NODE, host);
104 crm_xml_add(location, PCMK_XA_SCORE, PCMK_VALUE_MINUS_INFINITY);
105
106 } else {
107 xmlNode *rule = pcmk__xe_create(location, PCMK_XE_RULE);
108 xmlNode *expr = pcmk__xe_create(rule, PCMK_XE_EXPRESSION);
109
110 pcmk__xe_set_id(rule, "cli-ban-%s-on-%s-rule", rsc_id, host);
111 crm_xml_add(rule, PCMK_XA_SCORE, PCMK_VALUE_MINUS_INFINITY);
112 crm_xml_add(rule, PCMK_XA_BOOLEAN_OP, PCMK_VALUE_AND);
113
114 pcmk__xe_set_id(expr, "cli-ban-%s-on-%s-expr", rsc_id, host);
115 crm_xml_add(expr, PCMK_XA_ATTRIBUTE, CRM_ATTR_UNAME);
116 crm_xml_add(expr, PCMK_XA_OPERATION, PCMK_VALUE_EQ);
117 crm_xml_add(expr, PCMK_XA_VALUE, host);
118 crm_xml_add(expr, PCMK_XA_TYPE, PCMK_VALUE_STRING);
119
120 expr = pcmk__xe_create(rule, PCMK_XE_DATE_EXPRESSION);
121 pcmk__xe_set_id(expr, "cli-ban-%s-on-%s-lifetime", rsc_id, host);
122 crm_xml_add(expr, PCMK_XA_OPERATION, PCMK_VALUE_LT);
123 crm_xml_add(expr, PCMK_XA_END, later_s);
124 }
125
126 crm_log_xml_notice(fragment, "Modify");
127 rc = cib_conn->cmds->modify(cib_conn, PCMK_XE_CONSTRAINTS, fragment,
128 cib_sync_call);
129 rc = pcmk_legacy2rc(rc);
130
131 pcmk__xml_free(fragment);
132 free(later_s);
133
134 if ((rc != pcmk_rc_ok)
135 && promoted_role_only
136 && (strcmp(promoted_role, PCMK_ROLE_PROMOTED) == 0)) {
137
138 int banrc = cli_resource_ban(out, rsc_id, host, move_lifetime,
139 cib_conn, promoted_role_only,
140 PCMK__ROLE_PROMOTED_LEGACY);
141 if (banrc == pcmk_rc_ok) {
142 rc = banrc;
143 }
144 }
145
146 return rc;
147 }
148
149
150 int
151 cli_resource_prefer(pcmk__output_t *out,const char *rsc_id, const char *host,
152 const char *move_lifetime, cib_t *cib_conn,
153 gboolean promoted_role_only, const char *promoted_role)
154 {
155 char *later_s = parse_cli_lifetime(out, move_lifetime);
156 int rc = pcmk_rc_ok;
157 xmlNode *location = NULL;
158 xmlNode *fragment = NULL;
159
160 if(move_lifetime && later_s == NULL) {
161 return EINVAL;
162 }
163
164 if(cib_conn == NULL) {
165 free(later_s);
166 return ENOTCONN;
167 }
168
169 fragment = pcmk__xe_create(NULL, PCMK_XE_CONSTRAINTS);
170
171 location = pcmk__xe_create(fragment, PCMK_XE_RSC_LOCATION);
172 pcmk__xe_set_id(location, "cli-prefer-%s", rsc_id);
173
174 crm_xml_add(location, PCMK_XA_RSC, rsc_id);
175 if(promoted_role_only) {
176 crm_xml_add(location, PCMK_XA_ROLE, promoted_role);
177 } else {
178 crm_xml_add(location, PCMK_XA_ROLE, PCMK_ROLE_STARTED);
179 }
180
181 if (later_s == NULL) {
182
183 crm_xml_add(location, PCMK_XE_NODE, host);
184 crm_xml_add(location, PCMK_XA_SCORE, PCMK_VALUE_INFINITY);
185
186 } else {
187 xmlNode *rule = pcmk__xe_create(location, PCMK_XE_RULE);
188 xmlNode *expr = pcmk__xe_create(rule, PCMK_XE_EXPRESSION);
189
190 pcmk__xe_set_id(rule, "cli-prefer-rule-%s", rsc_id);
191 crm_xml_add(rule, PCMK_XA_SCORE, PCMK_VALUE_INFINITY);
192 crm_xml_add(rule, PCMK_XA_BOOLEAN_OP, PCMK_VALUE_AND);
193
194 pcmk__xe_set_id(expr, "cli-prefer-expr-%s", rsc_id);
195 crm_xml_add(expr, PCMK_XA_ATTRIBUTE, CRM_ATTR_UNAME);
196 crm_xml_add(expr, PCMK_XA_OPERATION, PCMK_VALUE_EQ);
197 crm_xml_add(expr, PCMK_XA_VALUE, host);
198 crm_xml_add(expr, PCMK_XA_TYPE, PCMK_VALUE_STRING);
199
200 expr = pcmk__xe_create(rule, PCMK_XE_DATE_EXPRESSION);
201 pcmk__xe_set_id(expr, "cli-prefer-lifetime-end-%s", rsc_id);
202 crm_xml_add(expr, PCMK_XA_OPERATION, PCMK_VALUE_LT);
203 crm_xml_add(expr, PCMK_XA_END, later_s);
204 }
205
206 crm_log_xml_info(fragment, "Modify");
207 rc = cib_conn->cmds->modify(cib_conn, PCMK_XE_CONSTRAINTS, fragment,
208 cib_sync_call);
209 rc = pcmk_legacy2rc(rc);
210
211 pcmk__xml_free(fragment);
212 free(later_s);
213
214 if ((rc != pcmk_rc_ok)
215 && promoted_role_only
216 && (strcmp(promoted_role, PCMK_ROLE_PROMOTED) == 0)) {
217
218 int preferrc = cli_resource_prefer(out, rsc_id, host, move_lifetime,
219 cib_conn, promoted_role_only,
220 PCMK__ROLE_PROMOTED_LEGACY);
221 if (preferrc == pcmk_rc_ok) {
222 rc = preferrc;
223 }
224 }
225
226 return rc;
227 }
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250 static int
251 resource_clear_node_in_expr(const char *rsc_id, const char *host,
252 cib_t *cib_conn)
253 {
254 int rc = pcmk_rc_ok;
255 char *xpath_string = NULL;
256
257 #define XPATH_FMT \
258 "//" PCMK_XE_RSC_LOCATION "[@" PCMK_XA_ID "='cli-prefer-%s']" \
259 "[" PCMK_XE_RULE \
260 "[@" PCMK_XA_ID "='cli-prefer-rule-%s']" \
261 "/" PCMK_XE_EXPRESSION \
262 "[@" PCMK_XA_ATTRIBUTE "='" CRM_ATTR_UNAME "' " \
263 "and @" PCMK_XA_VALUE "='%s']" \
264 "]"
265
266 xpath_string = crm_strdup_printf(XPATH_FMT, rsc_id, rsc_id, host);
267
268 rc = cib_conn->cmds->remove(cib_conn, xpath_string, NULL,
269 cib_xpath|cib_sync_call);
270 if (rc == -ENXIO) {
271 rc = pcmk_rc_ok;
272 } else {
273 rc = pcmk_legacy2rc(rc);
274 }
275
276 free(xpath_string);
277 return rc;
278 }
279
280
281 static int
282 resource_clear_node_in_location(const char *rsc_id, const char *host, cib_t * cib_conn,
283 bool clear_ban_constraints, gboolean force)
284 {
285 int rc = pcmk_rc_ok;
286 xmlNode *fragment = NULL;
287 xmlNode *location = NULL;
288
289 fragment = pcmk__xe_create(NULL, PCMK_XE_CONSTRAINTS);
290
291 if (clear_ban_constraints == TRUE) {
292 location = pcmk__xe_create(fragment, PCMK_XE_RSC_LOCATION);
293 pcmk__xe_set_id(location, "cli-ban-%s-on-%s", rsc_id, host);
294 }
295
296 location = pcmk__xe_create(fragment, PCMK_XE_RSC_LOCATION);
297 pcmk__xe_set_id(location, "cli-prefer-%s", rsc_id);
298 if (force == FALSE) {
299 crm_xml_add(location, PCMK_XE_NODE, host);
300 }
301
302 crm_log_xml_info(fragment, "Delete");
303 rc = cib_conn->cmds->remove(cib_conn, PCMK_XE_CONSTRAINTS, fragment,
304 cib_sync_call);
305 if (rc == -ENXIO) {
306 rc = pcmk_rc_ok;
307 } else {
308 rc = pcmk_legacy2rc(rc);
309 }
310
311 pcmk__xml_free(fragment);
312 return rc;
313 }
314
315
316 int
317 cli_resource_clear(const char *rsc_id, const char *host, GList *allnodes, cib_t * cib_conn,
318 bool clear_ban_constraints, gboolean force)
319 {
320 int rc = pcmk_rc_ok;
321
322 if(cib_conn == NULL) {
323 return ENOTCONN;
324 }
325
326 if (host) {
327 rc = resource_clear_node_in_expr(rsc_id, host, cib_conn);
328
329
330
331
332
333 if (rc == pcmk_rc_ok) {
334 rc = resource_clear_node_in_location(rsc_id, host, cib_conn,
335 clear_ban_constraints, force);
336 }
337
338 } else {
339 GList *n = allnodes;
340
341
342
343
344 for(; n; n = n->next) {
345 pcmk_node_t *target = n->data;
346
347 rc = cli_resource_clear(rsc_id, target->priv->name, NULL,
348 cib_conn, clear_ban_constraints, force);
349 if (rc != pcmk_rc_ok) {
350 break;
351 }
352 }
353 }
354
355 return rc;
356 }
357
358 static void
359 build_clear_xpath_string(GString *buf, const xmlNode *constraint_node,
360 const char *rsc, const char *node,
361 bool promoted_role_only)
362 {
363 const char *cons_id = pcmk__xe_id(constraint_node);
364 const char *cons_rsc = crm_element_value(constraint_node, PCMK_XA_RSC);
365 GString *rsc_role_substr = NULL;
366 const char *promoted_role_rule = "@" PCMK_XA_ROLE "='" PCMK_ROLE_PROMOTED
367 "' or @" PCMK_XA_ROLE "='"
368 PCMK__ROLE_PROMOTED_LEGACY "'";
369
370 pcmk__assert(buf != NULL);
371 g_string_truncate(buf, 0);
372
373 if (!pcmk__starts_with(cons_id, "cli-ban-")
374 && !pcmk__starts_with(cons_id, "cli-prefer-")) {
375 return;
376 }
377
378 g_string_append(buf, "//" PCMK_XE_RSC_LOCATION);
379
380 if ((node != NULL) || (rsc != NULL) || promoted_role_only) {
381 g_string_append_c(buf, '[');
382
383 if (node != NULL) {
384 pcmk__g_strcat(buf, "@" PCMK_XE_NODE "='", node, "'", NULL);
385
386 if (promoted_role_only || (rsc != NULL)) {
387 g_string_append(buf, " and ");
388 }
389 }
390
391 if ((rsc != NULL) && promoted_role_only) {
392 rsc_role_substr = g_string_sized_new(64);
393 pcmk__g_strcat(rsc_role_substr,
394 "@" PCMK_XA_RSC "='", rsc, "' "
395 "and (" , promoted_role_rule, ")", NULL);
396
397 } else if (rsc != NULL) {
398 rsc_role_substr = g_string_sized_new(64);
399 pcmk__g_strcat(rsc_role_substr,
400 "@" PCMK_XA_RSC "='", rsc, "'", NULL);
401
402 } else if (promoted_role_only) {
403 rsc_role_substr = g_string_sized_new(64);
404 g_string_append(rsc_role_substr, promoted_role_rule);
405 }
406
407 if (rsc_role_substr != NULL) {
408 g_string_append(buf, rsc_role_substr->str);
409 }
410 g_string_append_c(buf, ']');
411 }
412
413 if (node != NULL) {
414 g_string_append(buf, "|//" PCMK_XE_RSC_LOCATION);
415
416 if (rsc_role_substr != NULL) {
417 pcmk__g_strcat(buf, "[", rsc_role_substr, "]", NULL);
418 }
419 pcmk__g_strcat(buf,
420 "/" PCMK_XE_RULE "[" PCMK_XE_EXPRESSION
421 "[@" PCMK_XA_ATTRIBUTE "='" CRM_ATTR_UNAME "' "
422 "and @" PCMK_XA_VALUE "='", node, "']]", NULL);
423 }
424
425 g_string_append(buf, "//" PCMK_XE_DATE_EXPRESSION "[@" PCMK_XA_ID "='");
426 if (pcmk__starts_with(cons_id, "cli-ban-")) {
427 pcmk__g_strcat(buf, cons_id, "-lifetime']", NULL);
428
429 } else {
430 pcmk__g_strcat(buf,
431 "cli-prefer-lifetime-end-", cons_rsc, "']", NULL);
432 }
433
434 if (rsc_role_substr != NULL) {
435 g_string_free(rsc_role_substr, TRUE);
436 }
437 }
438
439
440 int
441 cli_resource_clear_all_expired(xmlNode *root, cib_t *cib_conn, const char *rsc,
442 const char *node, gboolean promoted_role_only)
443 {
444 GString *buf = NULL;
445 xmlXPathObject *xpathObj = NULL;
446 xmlNode *cib_constraints = NULL;
447 crm_time_t *now = crm_time_new(NULL);
448 int num_results = 0;
449 int rc = pcmk_rc_ok;
450
451 cib_constraints = pcmk_find_cib_element(root, PCMK_XE_CONSTRAINTS);
452 xpathObj = pcmk__xpath_search(cib_constraints->doc,
453 "//" PCMK_XE_RSC_LOCATION);
454 num_results = pcmk__xpath_num_results(xpathObj);
455
456 for (int i = 0; i < num_results; i++) {
457 xmlNode *constraint_node = pcmk__xpath_result(xpathObj, i);
458 xmlNode *date_expr_node = NULL;
459 crm_time_t *end = NULL;
460 int rc = pcmk_rc_ok;
461
462 if (constraint_node == NULL) {
463 continue;
464 }
465
466 if (buf == NULL) {
467 buf = g_string_sized_new(1024);
468 }
469
470 build_clear_xpath_string(buf, constraint_node, rsc, node,
471 promoted_role_only);
472 if (buf->len == 0) {
473 continue;
474 }
475
476 date_expr_node = pcmk__xpath_find_one(constraint_node->doc, buf->str,
477 LOG_DEBUG);
478 if (date_expr_node == NULL) {
479 continue;
480 }
481
482
483
484
485 rc = pcmk__xe_get_datetime(date_expr_node, PCMK_XA_END, &end);
486 if (rc != pcmk_rc_ok) {
487 crm_trace("Date expression %s has invalid " PCMK_XA_END ": %s",
488 pcmk__s(pcmk__xe_id(date_expr_node), "without ID"),
489 pcmk_rc_str(rc));
490 continue;
491 }
492
493 if (crm_time_compare(now, end) == 1) {
494 xmlNode *fragment = NULL;
495 xmlNode *location = NULL;
496
497 fragment = pcmk__xe_create(NULL, PCMK_XE_CONSTRAINTS);
498 location = pcmk__xe_create(fragment, PCMK_XE_RSC_LOCATION);
499 pcmk__xe_set_id(location, "%s", pcmk__xe_id(constraint_node));
500 crm_log_xml_info(fragment, "Delete");
501
502 rc = cib_conn->cmds->remove(cib_conn, PCMK_XE_CONSTRAINTS, fragment,
503 cib_sync_call);
504 rc = pcmk_legacy2rc(rc);
505
506 if (rc != pcmk_rc_ok) {
507 goto done;
508 }
509
510 pcmk__xml_free(fragment);
511 }
512
513 crm_time_free(end);
514 }
515
516 done:
517 if (buf != NULL) {
518 g_string_free(buf, TRUE);
519 }
520 xmlXPathFreeObject(xpathObj);
521 crm_time_free(now);
522 return rc;
523 }