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