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