This source file includes following definitions.
- parse_cli_lifetime
- promoted_role_name
- 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 static const char *
60 promoted_role_name(void)
61 {
62
63
64
65
66 #ifdef PCMK__COMPAT_2_0
67 return RSC_ROLE_PROMOTED_LEGACY_S;
68 #else
69 return RSC_ROLE_PROMOTED_S;
70 #endif
71 }
72
73
74 int
75 cli_resource_ban(pcmk__output_t *out, const char *rsc_id, const char *host,
76 const char *move_lifetime, GList *allnodes, cib_t * cib_conn,
77 int cib_options, gboolean promoted_role_only)
78 {
79 char *later_s = NULL;
80 int rc = pcmk_rc_ok;
81 xmlNode *fragment = NULL;
82 xmlNode *location = NULL;
83
84 if(host == NULL) {
85 GList *n = allnodes;
86 for(; n && rc == pcmk_rc_ok; n = n->next) {
87 pe_node_t *target = n->data;
88
89 rc = cli_resource_ban(out, rsc_id, target->details->uname, move_lifetime,
90 NULL, cib_conn, cib_options, promoted_role_only);
91 }
92 return rc;
93 }
94
95 later_s = parse_cli_lifetime(out, move_lifetime);
96 if(move_lifetime && later_s == NULL) {
97 return EINVAL;
98 }
99
100 fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
101
102 location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
103 crm_xml_set_id(location, "cli-ban-%s-on-%s", rsc_id, host);
104
105 out->info(out, "WARNING: Creating rsc_location constraint '%s' with a "
106 "score of -INFINITY for resource %s on %s.\n\tThis will "
107 "prevent %s from %s on %s until the constraint is removed "
108 "using the clear option or by editing the CIB with an "
109 "appropriate tool\n\tThis will be the case even if %s "
110 "is the last node in the cluster",
111 ID(location), rsc_id, host, rsc_id,
112 (promoted_role_only? "being promoted" : "running"),
113 host, host);
114
115 crm_xml_add(location, XML_LOC_ATTR_SOURCE, rsc_id);
116 if(promoted_role_only) {
117 crm_xml_add(location, XML_RULE_ATTR_ROLE, promoted_role_name());
118 } else {
119 crm_xml_add(location, XML_RULE_ATTR_ROLE, RSC_ROLE_STARTED_S);
120 }
121
122 if (later_s == NULL) {
123
124 crm_xml_add(location, XML_CIB_TAG_NODE, host);
125 crm_xml_add(location, XML_RULE_ATTR_SCORE, CRM_MINUS_INFINITY_S);
126
127 } else {
128 xmlNode *rule = create_xml_node(location, XML_TAG_RULE);
129 xmlNode *expr = create_xml_node(rule, XML_TAG_EXPRESSION);
130
131 crm_xml_set_id(rule, "cli-ban-%s-on-%s-rule", rsc_id, host);
132 crm_xml_add(rule, XML_RULE_ATTR_SCORE, CRM_MINUS_INFINITY_S);
133 crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and");
134
135 crm_xml_set_id(expr, "cli-ban-%s-on-%s-expr", rsc_id, host);
136 crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, CRM_ATTR_UNAME);
137 crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq");
138 crm_xml_add(expr, XML_EXPR_ATTR_VALUE, host);
139 crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string");
140
141 expr = create_xml_node(rule, "date_expression");
142 crm_xml_set_id(expr, "cli-ban-%s-on-%s-lifetime", rsc_id, host);
143 crm_xml_add(expr, "operation", "lt");
144 crm_xml_add(expr, "end", later_s);
145 }
146
147 crm_log_xml_notice(fragment, "Modify");
148 rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment,
149 cib_options);
150 rc = pcmk_legacy2rc(rc);
151
152 free_xml(fragment);
153 free(later_s);
154 return rc;
155 }
156
157
158 int
159 cli_resource_prefer(pcmk__output_t *out,const char *rsc_id, const char *host,
160 const char *move_lifetime, cib_t * cib_conn, int cib_options,
161 gboolean promoted_role_only)
162 {
163 char *later_s = parse_cli_lifetime(out, move_lifetime);
164 int rc = pcmk_rc_ok;
165 xmlNode *location = NULL;
166 xmlNode *fragment = NULL;
167
168 if(move_lifetime && later_s == NULL) {
169 return EINVAL;
170 }
171
172 if(cib_conn == NULL) {
173 free(later_s);
174 return ENOTCONN;
175 }
176
177 fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
178
179 location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
180 crm_xml_set_id(location, "cli-prefer-%s", rsc_id);
181
182 crm_xml_add(location, XML_LOC_ATTR_SOURCE, rsc_id);
183 if(promoted_role_only) {
184 crm_xml_add(location, XML_RULE_ATTR_ROLE, promoted_role_name());
185 } else {
186 crm_xml_add(location, XML_RULE_ATTR_ROLE, RSC_ROLE_STARTED_S);
187 }
188
189 if (later_s == NULL) {
190
191 crm_xml_add(location, XML_CIB_TAG_NODE, host);
192 crm_xml_add(location, XML_RULE_ATTR_SCORE, CRM_INFINITY_S);
193
194 } else {
195 xmlNode *rule = create_xml_node(location, XML_TAG_RULE);
196 xmlNode *expr = create_xml_node(rule, XML_TAG_EXPRESSION);
197
198 crm_xml_set_id(rule, "cli-prefer-rule-%s", rsc_id);
199 crm_xml_add(rule, XML_RULE_ATTR_SCORE, CRM_INFINITY_S);
200 crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and");
201
202 crm_xml_set_id(expr, "cli-prefer-expr-%s", rsc_id);
203 crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, CRM_ATTR_UNAME);
204 crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq");
205 crm_xml_add(expr, XML_EXPR_ATTR_VALUE, host);
206 crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string");
207
208 expr = create_xml_node(rule, "date_expression");
209 crm_xml_set_id(expr, "cli-prefer-lifetime-end-%s", rsc_id);
210 crm_xml_add(expr, "operation", "lt");
211 crm_xml_add(expr, "end", later_s);
212 }
213
214 crm_log_xml_info(fragment, "Modify");
215 rc = cib_conn->cmds->modify(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment,
216 cib_options);
217 rc = pcmk_legacy2rc(rc);
218
219 free_xml(fragment);
220 free(later_s);
221 return rc;
222 }
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244 static int
245 resource_clear_node_in_expr(const char *rsc_id, const char *host, cib_t * cib_conn,
246 int cib_options)
247 {
248 int rc = pcmk_rc_ok;
249 char *xpath_string = NULL;
250
251 #define XPATH_FMT \
252 "//" XML_CONS_TAG_RSC_LOCATION "[@" XML_ATTR_ID "='cli-prefer-%s']" \
253 "[" XML_TAG_RULE \
254 "[@" XML_ATTR_ID "='cli-prefer-rule-%s']" \
255 "/" XML_TAG_EXPRESSION \
256 "[@" XML_EXPR_ATTR_ATTRIBUTE "='#uname' " \
257 "and @" XML_EXPR_ATTR_VALUE "='%s']" \
258 "]"
259
260 xpath_string = crm_strdup_printf(XPATH_FMT, rsc_id, rsc_id, host);
261
262 rc = cib_conn->cmds->remove(cib_conn, xpath_string, NULL, cib_xpath | cib_options);
263 if (rc == -ENXIO) {
264 rc = pcmk_rc_ok;
265 } else {
266 rc = pcmk_legacy2rc(rc);
267 }
268
269 free(xpath_string);
270 return rc;
271 }
272
273
274 static int
275 resource_clear_node_in_location(const char *rsc_id, const char *host, cib_t * cib_conn,
276 int cib_options, bool clear_ban_constraints, gboolean force)
277 {
278 int rc = pcmk_rc_ok;
279 xmlNode *fragment = NULL;
280 xmlNode *location = NULL;
281
282 fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
283
284 if (clear_ban_constraints == TRUE) {
285 location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
286 crm_xml_set_id(location, "cli-ban-%s-on-%s", rsc_id, host);
287 }
288
289 location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
290 crm_xml_set_id(location, "cli-prefer-%s", rsc_id);
291 if (force == FALSE) {
292 crm_xml_add(location, XML_CIB_TAG_NODE, host);
293 }
294
295 crm_log_xml_info(fragment, "Delete");
296 rc = cib_conn->cmds->remove(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, cib_options);
297 if (rc == -ENXIO) {
298 rc = pcmk_rc_ok;
299 } else {
300 rc = pcmk_legacy2rc(rc);
301 }
302
303 free_xml(fragment);
304 return rc;
305 }
306
307
308 int
309 cli_resource_clear(const char *rsc_id, const char *host, GList *allnodes, cib_t * cib_conn,
310 int cib_options, bool clear_ban_constraints, gboolean force)
311 {
312 int rc = pcmk_rc_ok;
313
314 if(cib_conn == NULL) {
315 return ENOTCONN;
316 }
317
318 if (host) {
319 rc = resource_clear_node_in_expr(rsc_id, host, cib_conn, cib_options);
320
321
322
323
324
325 if (rc == pcmk_rc_ok) {
326 rc = resource_clear_node_in_location(rsc_id, host, cib_conn,
327 cib_options, clear_ban_constraints,
328 force);
329 }
330
331 } else {
332 GList *n = allnodes;
333
334
335
336
337 for(; n; n = n->next) {
338 pe_node_t *target = n->data;
339
340 rc = cli_resource_clear(rsc_id, target->details->uname, NULL,
341 cib_conn, cib_options, clear_ban_constraints,
342 force);
343 if (rc != pcmk_rc_ok) {
344 break;
345 }
346 }
347 }
348
349 return rc;
350 }
351
352 static void
353 build_clear_xpath_string(GString *buf, const xmlNode *constraint_node,
354 const char *rsc, const char *node,
355 bool promoted_role_only)
356 {
357 const char *cons_id = ID(constraint_node);
358 const char *cons_rsc = crm_element_value(constraint_node,
359 XML_LOC_ATTR_SOURCE);
360 GString *rsc_role_substr = NULL;
361
362 CRM_ASSERT(buf != NULL);
363 g_string_truncate(buf, 0);
364
365 if (!pcmk__starts_with(cons_id, "cli-ban-")
366 && !pcmk__starts_with(cons_id, "cli-prefer-")) {
367 return;
368 }
369
370 g_string_append(buf, "//" XML_CONS_TAG_RSC_LOCATION);
371
372 if ((node != NULL) || (rsc != NULL) || promoted_role_only) {
373 g_string_append_c(buf, '[');
374
375 if (node != NULL) {
376 pcmk__g_strcat(buf, "@" XML_CIB_TAG_NODE "='", node, "'", NULL);
377
378 if (promoted_role_only || (rsc != NULL)) {
379 g_string_append(buf, " and ");
380 }
381 }
382
383 if ((rsc != NULL) && promoted_role_only) {
384 rsc_role_substr = g_string_sized_new(64);
385 pcmk__g_strcat(rsc_role_substr,
386 "@" XML_LOC_ATTR_SOURCE "='", rsc, "' "
387 "and @" XML_RULE_ATTR_ROLE "='",
388 promoted_role_name(), "'", NULL);
389
390 } else if (rsc != NULL) {
391 rsc_role_substr = g_string_sized_new(64);
392 pcmk__g_strcat(rsc_role_substr,
393 "@" XML_LOC_ATTR_SOURCE "='", rsc, "'", NULL);
394
395 } else if (promoted_role_only) {
396 rsc_role_substr = g_string_sized_new(64);
397 pcmk__g_strcat(rsc_role_substr,
398 "@" XML_RULE_ATTR_ROLE "='", promoted_role_name(),
399 "'", NULL);
400 }
401
402 if (rsc_role_substr != NULL) {
403 g_string_append(buf, rsc_role_substr->str);
404 }
405 g_string_append_c(buf, ']');
406 }
407
408 if (node != NULL) {
409 g_string_append(buf, "|//" XML_CONS_TAG_RSC_LOCATION);
410
411 if (rsc_role_substr != NULL) {
412 pcmk__g_strcat(buf, "[", rsc_role_substr, "]", NULL);
413 }
414 pcmk__g_strcat(buf,
415 "/" XML_TAG_RULE "[" XML_TAG_EXPRESSION
416 "[@" XML_EXPR_ATTR_ATTRIBUTE "='" CRM_ATTR_UNAME "' "
417 "and @" XML_EXPR_ATTR_VALUE "='", node, "']]", NULL);
418 }
419
420 g_string_append(buf, "//" PCMK_XE_DATE_EXPRESSION "[@" XML_ATTR_ID "='");
421 if (pcmk__starts_with(cons_id, "cli-ban-")) {
422 pcmk__g_strcat(buf, cons_id, "-lifetime']", NULL);
423
424 } else {
425 pcmk__g_strcat(buf,
426 "cli-prefer-lifetime-end-", cons_rsc, "']", NULL);
427 }
428
429 if (rsc_role_substr != NULL) {
430 g_string_free(rsc_role_substr, TRUE);
431 }
432 }
433
434
435 int
436 cli_resource_clear_all_expired(xmlNode *root, cib_t *cib_conn, int cib_options,
437 const char *rsc, const char *node, gboolean promoted_role_only)
438 {
439 GString *buf = NULL;
440 xmlXPathObject *xpathObj = NULL;
441 xmlNode *cib_constraints = NULL;
442 crm_time_t *now = crm_time_new(NULL);
443 int i;
444 int rc = pcmk_rc_ok;
445
446 cib_constraints = pcmk_find_cib_element(root, XML_CIB_TAG_CONSTRAINTS);
447 xpathObj = xpath_search(cib_constraints, "//" XML_CONS_TAG_RSC_LOCATION);
448
449 for (i = 0; i < numXpathResults(xpathObj); i++) {
450 xmlNode *constraint_node = getXpathResult(xpathObj, i);
451 xmlNode *date_expr_node = NULL;
452 crm_time_t *end = NULL;
453
454 if (buf == NULL) {
455 buf = g_string_sized_new(1024);
456 }
457
458 build_clear_xpath_string(buf, constraint_node, rsc, node,
459 promoted_role_only);
460 if (buf->len == 0) {
461 continue;
462 }
463
464 date_expr_node = get_xpath_object((const char *) buf->str,
465 constraint_node, LOG_DEBUG);
466 if (date_expr_node == NULL) {
467 continue;
468 }
469
470
471
472
473 end = crm_time_new(crm_element_value(date_expr_node, "end"));
474
475 if (crm_time_compare(now, end) == 1) {
476 xmlNode *fragment = NULL;
477 xmlNode *location = NULL;
478
479 fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
480 location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
481 crm_xml_set_id(location, "%s", ID(constraint_node));
482 crm_log_xml_info(fragment, "Delete");
483
484 rc = cib_conn->cmds->remove(cib_conn, XML_CIB_TAG_CONSTRAINTS,
485 fragment, cib_options);
486 rc = pcmk_legacy2rc(rc);
487
488 if (rc != pcmk_rc_ok) {
489 goto done;
490 }
491
492 free_xml(fragment);
493 }
494
495 crm_time_free(end);
496 }
497
498 done:
499 if (buf != NULL) {
500 g_string_free(buf, TRUE);
501 }
502 freeXpathObject(xpathObj);
503 crm_time_free(now);
504 return rc;
505 }