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, int cib_options,
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 crm_xml_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 crm_xml_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 crm_xml_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 crm_xml_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_options);
126 rc = pcmk_legacy2rc(rc);
127
128 free_xml(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, cib_options, 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, int cib_options,
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 crm_xml_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 crm_xml_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 crm_xml_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 crm_xml_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_options);
206 rc = pcmk_legacy2rc(rc);
207
208 free_xml(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, cib_options, 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, cib_t * cib_conn,
249 int cib_options)
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, cib_xpath | cib_options);
266 if (rc == -ENXIO) {
267 rc = pcmk_rc_ok;
268 } else {
269 rc = pcmk_legacy2rc(rc);
270 }
271
272 free(xpath_string);
273 return rc;
274 }
275
276
277 static int
278 resource_clear_node_in_location(const char *rsc_id, const char *host, cib_t * cib_conn,
279 int cib_options, bool clear_ban_constraints, gboolean force)
280 {
281 int rc = pcmk_rc_ok;
282 xmlNode *fragment = NULL;
283 xmlNode *location = NULL;
284
285 fragment = pcmk__xe_create(NULL, PCMK_XE_CONSTRAINTS);
286
287 if (clear_ban_constraints == TRUE) {
288 location = pcmk__xe_create(fragment, PCMK_XE_RSC_LOCATION);
289 crm_xml_set_id(location, "cli-ban-%s-on-%s", rsc_id, host);
290 }
291
292 location = pcmk__xe_create(fragment, PCMK_XE_RSC_LOCATION);
293 crm_xml_set_id(location, "cli-prefer-%s", rsc_id);
294 if (force == FALSE) {
295 crm_xml_add(location, PCMK_XE_NODE, host);
296 }
297
298 crm_log_xml_info(fragment, "Delete");
299 rc = cib_conn->cmds->remove(cib_conn, PCMK_XE_CONSTRAINTS, fragment,
300 cib_options);
301 if (rc == -ENXIO) {
302 rc = pcmk_rc_ok;
303 } else {
304 rc = pcmk_legacy2rc(rc);
305 }
306
307 free_xml(fragment);
308 return rc;
309 }
310
311
312 int
313 cli_resource_clear(const char *rsc_id, const char *host, GList *allnodes, cib_t * cib_conn,
314 int cib_options, bool clear_ban_constraints, gboolean force)
315 {
316 int rc = pcmk_rc_ok;
317
318 if(cib_conn == NULL) {
319 return ENOTCONN;
320 }
321
322 if (host) {
323 rc = resource_clear_node_in_expr(rsc_id, host, cib_conn, cib_options);
324
325
326
327
328
329 if (rc == pcmk_rc_ok) {
330 rc = resource_clear_node_in_location(rsc_id, host, cib_conn,
331 cib_options, clear_ban_constraints,
332 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->details->uname, NULL,
345 cib_conn, cib_options, clear_ban_constraints,
346 force);
347 if (rc != pcmk_rc_ok) {
348 break;
349 }
350 }
351 }
352
353 return rc;
354 }
355
356 static void
357 build_clear_xpath_string(GString *buf, const xmlNode *constraint_node,
358 const char *rsc, const char *node,
359 bool promoted_role_only)
360 {
361 const char *cons_id = pcmk__xe_id(constraint_node);
362 const char *cons_rsc = crm_element_value(constraint_node, PCMK_XA_RSC);
363 GString *rsc_role_substr = NULL;
364 const char *promoted_role_rule = "@" PCMK_XA_ROLE "='" PCMK_ROLE_PROMOTED
365 "' or @" PCMK_XA_ROLE "='"
366 PCMK__ROLE_PROMOTED_LEGACY "'";
367
368 pcmk__assert(buf != NULL);
369 g_string_truncate(buf, 0);
370
371 if (!pcmk__starts_with(cons_id, "cli-ban-")
372 && !pcmk__starts_with(cons_id, "cli-prefer-")) {
373 return;
374 }
375
376 g_string_append(buf, "//" PCMK_XE_RSC_LOCATION);
377
378 if ((node != NULL) || (rsc != NULL) || promoted_role_only) {
379 g_string_append_c(buf, '[');
380
381 if (node != NULL) {
382 pcmk__g_strcat(buf, "@" PCMK_XE_NODE "='", node, "'", NULL);
383
384 if (promoted_role_only || (rsc != NULL)) {
385 g_string_append(buf, " and ");
386 }
387 }
388
389 if ((rsc != NULL) && promoted_role_only) {
390 rsc_role_substr = g_string_sized_new(64);
391 pcmk__g_strcat(rsc_role_substr,
392 "@" PCMK_XA_RSC "='", rsc, "' "
393 "and (" , promoted_role_rule, ")", NULL);
394
395 } else if (rsc != NULL) {
396 rsc_role_substr = g_string_sized_new(64);
397 pcmk__g_strcat(rsc_role_substr,
398 "@" PCMK_XA_RSC "='", rsc, "'", NULL);
399
400 } else if (promoted_role_only) {
401 rsc_role_substr = g_string_sized_new(64);
402 g_string_append(rsc_role_substr, promoted_role_rule);
403 }
404
405 if (rsc_role_substr != NULL) {
406 g_string_append(buf, rsc_role_substr->str);
407 }
408 g_string_append_c(buf, ']');
409 }
410
411 if (node != NULL) {
412 g_string_append(buf, "|//" PCMK_XE_RSC_LOCATION);
413
414 if (rsc_role_substr != NULL) {
415 pcmk__g_strcat(buf, "[", rsc_role_substr, "]", NULL);
416 }
417 pcmk__g_strcat(buf,
418 "/" PCMK_XE_RULE "[" PCMK_XE_EXPRESSION
419 "[@" PCMK_XA_ATTRIBUTE "='" CRM_ATTR_UNAME "' "
420 "and @" PCMK_XA_VALUE "='", node, "']]", NULL);
421 }
422
423 g_string_append(buf, "//" PCMK_XE_DATE_EXPRESSION "[@" PCMK_XA_ID "='");
424 if (pcmk__starts_with(cons_id, "cli-ban-")) {
425 pcmk__g_strcat(buf, cons_id, "-lifetime']", NULL);
426
427 } else {
428 pcmk__g_strcat(buf,
429 "cli-prefer-lifetime-end-", cons_rsc, "']", NULL);
430 }
431
432 if (rsc_role_substr != NULL) {
433 g_string_free(rsc_role_substr, TRUE);
434 }
435 }
436
437
438 int
439 cli_resource_clear_all_expired(xmlNode *root, cib_t *cib_conn, int cib_options,
440 const char *rsc, const char *node, gboolean promoted_role_only)
441 {
442 GString *buf = NULL;
443 xmlXPathObject *xpathObj = NULL;
444 xmlNode *cib_constraints = NULL;
445 crm_time_t *now = crm_time_new(NULL);
446 int i;
447 int rc = pcmk_rc_ok;
448
449 cib_constraints = pcmk_find_cib_element(root, PCMK_XE_CONSTRAINTS);
450 xpathObj = xpath_search(cib_constraints, "//" PCMK_XE_RSC_LOCATION);
451
452 for (i = 0; i < numXpathResults(xpathObj); i++) {
453 xmlNode *constraint_node = getXpathResult(xpathObj, i);
454 xmlNode *date_expr_node = NULL;
455 crm_time_t *end = NULL;
456 int rc = pcmk_rc_ok;
457
458 if (buf == NULL) {
459 buf = g_string_sized_new(1024);
460 }
461
462 build_clear_xpath_string(buf, constraint_node, rsc, node,
463 promoted_role_only);
464 if (buf->len == 0) {
465 continue;
466 }
467
468 date_expr_node = get_xpath_object((const char *) buf->str,
469 constraint_node, LOG_DEBUG);
470 if (date_expr_node == NULL) {
471 continue;
472 }
473
474
475
476
477
478
479 rc = pcmk__xe_get_datetime(date_expr_node, PCMK_XA_END, &end);
480 if (rc != pcmk_rc_ok) {
481 crm_trace("Invalid " PCMK_XA_END ": %s", pcmk_rc_str(rc));
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 crm_xml_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_options);
495 rc = pcmk_legacy2rc(rc);
496
497 if (rc != pcmk_rc_ok) {
498 goto done;
499 }
500
501 free_xml(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 }