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 #define XPATH_MAX 1024
15
16 static char *
17 parse_cli_lifetime(pcmk__output_t *out, const char *move_lifetime)
18 {
19 char *later_s = NULL;
20 crm_time_t *now = NULL;
21 crm_time_t *later = NULL;
22 crm_time_t *duration = NULL;
23
24 if (move_lifetime == NULL) {
25 return NULL;
26 }
27
28 duration = crm_time_parse_duration(move_lifetime);
29 if (duration == NULL) {
30 out->err(out, "Invalid duration specified: %s\n"
31 "Please refer to https://en.wikipedia.org/wiki/ISO_8601#Durations "
32 "for examples of valid durations", move_lifetime);
33 return NULL;
34 }
35
36 now = crm_time_new(NULL);
37 later = crm_time_add(now, duration);
38 if (later == NULL) {
39 out->err(out, "Unable to add %s to current time\n"
40 "Please report to " PACKAGE_BUGREPORT " as possible bug",
41 move_lifetime);
42 crm_time_free(now);
43 crm_time_free(duration);
44 return NULL;
45 }
46
47 crm_time_log(LOG_INFO, "now ", now,
48 crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
49 crm_time_log(LOG_INFO, "later ", later,
50 crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
51 crm_time_log(LOG_INFO, "duration", duration, crm_time_log_date | crm_time_log_timeofday);
52 later_s = crm_time_as_string(later, crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
53 out->info(out, "Migration will take effect until: %s", later_s);
54
55 crm_time_free(duration);
56 crm_time_free(later);
57 crm_time_free(now);
58 return later_s;
59 }
60
61 static const char *
62 promoted_role_name(void)
63 {
64
65
66
67
68 #ifdef PCMK__COMPAT_2_0
69 return RSC_ROLE_PROMOTED_LEGACY_S;
70 #else
71 return RSC_ROLE_PROMOTED_S;
72 #endif
73 }
74
75
76 int
77 cli_resource_ban(pcmk__output_t *out, const char *rsc_id, const char *host,
78 const char *move_lifetime, GList *allnodes, cib_t * cib_conn,
79 int cib_options, gboolean promoted_role_only)
80 {
81 char *later_s = NULL;
82 int rc = pcmk_rc_ok;
83 xmlNode *fragment = NULL;
84 xmlNode *location = NULL;
85
86 if(host == NULL) {
87 GList *n = allnodes;
88 for(; n && rc == pcmk_rc_ok; n = n->next) {
89 pe_node_t *target = n->data;
90
91 rc = cli_resource_ban(out, rsc_id, target->details->uname, move_lifetime,
92 NULL, cib_conn, cib_options, promoted_role_only);
93 }
94 return rc;
95 }
96
97 later_s = parse_cli_lifetime(out, move_lifetime);
98 if(move_lifetime && later_s == NULL) {
99 return EINVAL;
100 }
101
102 fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
103
104 location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
105 crm_xml_set_id(location, "cli-ban-%s-on-%s", rsc_id, host);
106
107 out->info(out, "WARNING: Creating rsc_location constraint '%s' with a "
108 "score of -INFINITY for resource %s on %s.\n\tThis will "
109 "prevent %s from %s on %s until the constraint is removed "
110 "using the clear option or by editing the CIB with an "
111 "appropriate tool\n\tThis will be the case even if %s "
112 "is the last node in the cluster",
113 ID(location), rsc_id, host, rsc_id,
114 (promoted_role_only? "being promoted" : "running"),
115 host, host);
116
117 crm_xml_add(location, XML_LOC_ATTR_SOURCE, rsc_id);
118 if(promoted_role_only) {
119 crm_xml_add(location, XML_RULE_ATTR_ROLE, promoted_role_name());
120 } else {
121 crm_xml_add(location, XML_RULE_ATTR_ROLE, RSC_ROLE_STARTED_S);
122 }
123
124 if (later_s == NULL) {
125
126 crm_xml_add(location, XML_CIB_TAG_NODE, host);
127 crm_xml_add(location, XML_RULE_ATTR_SCORE, CRM_MINUS_INFINITY_S);
128
129 } else {
130 xmlNode *rule = create_xml_node(location, XML_TAG_RULE);
131 xmlNode *expr = create_xml_node(rule, XML_TAG_EXPRESSION);
132
133 crm_xml_set_id(rule, "cli-ban-%s-on-%s-rule", rsc_id, host);
134 crm_xml_add(rule, XML_RULE_ATTR_SCORE, CRM_MINUS_INFINITY_S);
135 crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and");
136
137 crm_xml_set_id(expr, "cli-ban-%s-on-%s-expr", rsc_id, host);
138 crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, CRM_ATTR_UNAME);
139 crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq");
140 crm_xml_add(expr, XML_EXPR_ATTR_VALUE, host);
141 crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string");
142
143 expr = create_xml_node(rule, "date_expression");
144 crm_xml_set_id(expr, "cli-ban-%s-on-%s-lifetime", rsc_id, host);
145 crm_xml_add(expr, "operation", "lt");
146 crm_xml_add(expr, "end", later_s);
147 }
148
149 crm_log_xml_notice(fragment, "Modify");
150 rc = cib_conn->cmds->update(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, cib_options);
151 rc = pcmk_legacy2rc(rc);
152
153 free_xml(fragment);
154 free(later_s);
155 return rc;
156 }
157
158
159 int
160 cli_resource_prefer(pcmk__output_t *out,const char *rsc_id, const char *host,
161 const char *move_lifetime, cib_t * cib_conn, int cib_options,
162 gboolean promoted_role_only)
163 {
164 char *later_s = parse_cli_lifetime(out, move_lifetime);
165 int rc = pcmk_rc_ok;
166 xmlNode *location = NULL;
167 xmlNode *fragment = NULL;
168
169 if(move_lifetime && later_s == NULL) {
170 return EINVAL;
171 }
172
173 if(cib_conn == NULL) {
174 free(later_s);
175 return ENOTCONN;
176 }
177
178 fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
179
180 location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
181 crm_xml_set_id(location, "cli-prefer-%s", rsc_id);
182
183 crm_xml_add(location, XML_LOC_ATTR_SOURCE, rsc_id);
184 if(promoted_role_only) {
185 crm_xml_add(location, XML_RULE_ATTR_ROLE, promoted_role_name());
186 } else {
187 crm_xml_add(location, XML_RULE_ATTR_ROLE, RSC_ROLE_STARTED_S);
188 }
189
190 if (later_s == NULL) {
191
192 crm_xml_add(location, XML_CIB_TAG_NODE, host);
193 crm_xml_add(location, XML_RULE_ATTR_SCORE, CRM_INFINITY_S);
194
195 } else {
196 xmlNode *rule = create_xml_node(location, XML_TAG_RULE);
197 xmlNode *expr = create_xml_node(rule, XML_TAG_EXPRESSION);
198
199 crm_xml_set_id(rule, "cli-prefer-rule-%s", rsc_id);
200 crm_xml_add(rule, XML_RULE_ATTR_SCORE, CRM_INFINITY_S);
201 crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and");
202
203 crm_xml_set_id(expr, "cli-prefer-expr-%s", rsc_id);
204 crm_xml_add(expr, XML_EXPR_ATTR_ATTRIBUTE, CRM_ATTR_UNAME);
205 crm_xml_add(expr, XML_EXPR_ATTR_OPERATION, "eq");
206 crm_xml_add(expr, XML_EXPR_ATTR_VALUE, host);
207 crm_xml_add(expr, XML_EXPR_ATTR_TYPE, "string");
208
209 expr = create_xml_node(rule, "date_expression");
210 crm_xml_set_id(expr, "cli-prefer-lifetime-end-%s", rsc_id);
211 crm_xml_add(expr, "operation", "lt");
212 crm_xml_add(expr, "end", later_s);
213 }
214
215 crm_log_xml_info(fragment, "Modify");
216 rc = cib_conn->cmds->update(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, 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 xpath_string = crm_strdup_printf("//rsc_location[@id='cli-prefer-%s'][rule[@id='cli-prefer-rule-%s']/expression[@attribute='#uname' and @value='%s']]",
252 rsc_id, rsc_id, host);
253
254 rc = cib_conn->cmds->remove(cib_conn, xpath_string, NULL, cib_xpath | cib_options);
255 if (rc == -ENXIO) {
256 rc = pcmk_rc_ok;
257 } else {
258 rc = pcmk_legacy2rc(rc);
259 }
260
261 free(xpath_string);
262 return rc;
263 }
264
265
266 static int
267 resource_clear_node_in_location(const char *rsc_id, const char *host, cib_t * cib_conn,
268 int cib_options, bool clear_ban_constraints, gboolean force)
269 {
270 int rc = pcmk_rc_ok;
271 xmlNode *fragment = NULL;
272 xmlNode *location = NULL;
273
274 fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
275
276 if (clear_ban_constraints == TRUE) {
277 location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
278 crm_xml_set_id(location, "cli-ban-%s-on-%s", rsc_id, host);
279 }
280
281 location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
282 crm_xml_set_id(location, "cli-prefer-%s", rsc_id);
283 if (force == FALSE) {
284 crm_xml_add(location, XML_CIB_TAG_NODE, host);
285 }
286
287 crm_log_xml_info(fragment, "Delete");
288 rc = cib_conn->cmds->remove(cib_conn, XML_CIB_TAG_CONSTRAINTS, fragment, cib_options);
289 if (rc == -ENXIO) {
290 rc = pcmk_rc_ok;
291 } else {
292 rc = pcmk_legacy2rc(rc);
293 }
294
295 free_xml(fragment);
296 return rc;
297 }
298
299
300 int
301 cli_resource_clear(const char *rsc_id, const char *host, GList *allnodes, cib_t * cib_conn,
302 int cib_options, bool clear_ban_constraints, gboolean force)
303 {
304 int rc = pcmk_rc_ok;
305
306 if(cib_conn == NULL) {
307 return ENOTCONN;
308 }
309
310 if (host) {
311 rc = resource_clear_node_in_expr(rsc_id, host, cib_conn, cib_options);
312
313
314
315
316
317 if (rc == pcmk_rc_ok) {
318 rc = resource_clear_node_in_location(rsc_id, host, cib_conn,
319 cib_options, clear_ban_constraints,
320 force);
321 }
322
323 } else {
324 GList *n = allnodes;
325
326
327
328
329 for(; n; n = n->next) {
330 pe_node_t *target = n->data;
331
332 rc = cli_resource_clear(rsc_id, target->details->uname, NULL,
333 cib_conn, cib_options, clear_ban_constraints,
334 force);
335 if (rc != pcmk_rc_ok) {
336 break;
337 }
338 }
339 }
340
341 return rc;
342 }
343
344 static char *
345 build_clear_xpath_string(xmlNode *constraint_node, const char *rsc, const char *node, gboolean promoted_role_only)
346 {
347 int offset = 0;
348 char *xpath_string = NULL;
349 char *first_half = NULL;
350 char *rsc_role_substr = NULL;
351 char *date_substr = NULL;
352
353 if (pcmk__starts_with(ID(constraint_node), "cli-ban-")) {
354 date_substr = crm_strdup_printf("//date_expression[@id='%s-lifetime']",
355 ID(constraint_node));
356
357 } else if (pcmk__starts_with(ID(constraint_node), "cli-prefer-")) {
358 date_substr = crm_strdup_printf("//date_expression[@id='cli-prefer-lifetime-end-%s']",
359 crm_element_value(constraint_node, "rsc"));
360 } else {
361 return NULL;
362 }
363
364 first_half = calloc(1, XPATH_MAX);
365 offset += snprintf(first_half + offset, XPATH_MAX - offset, "//rsc_location");
366
367 if (node != NULL || rsc != NULL || promoted_role_only == TRUE) {
368 offset += snprintf(first_half + offset, XPATH_MAX - offset, "[");
369
370 if (node != NULL) {
371 if (rsc != NULL || promoted_role_only == TRUE) {
372 offset += snprintf(first_half + offset, XPATH_MAX - offset, "@node='%s' and ", node);
373 } else {
374 offset += snprintf(first_half + offset, XPATH_MAX - offset, "@node='%s'", node);
375 }
376 }
377
378 if (rsc != NULL && promoted_role_only == TRUE) {
379 rsc_role_substr = crm_strdup_printf("@rsc='%s' and @role='%s'",
380 rsc, promoted_role_name());
381 offset += snprintf(first_half + offset, XPATH_MAX - offset,
382 "@rsc='%s' and @role='%s']",
383 rsc, promoted_role_name());
384 } else if (rsc != NULL) {
385 rsc_role_substr = crm_strdup_printf("@rsc='%s'", rsc);
386 offset += snprintf(first_half + offset, XPATH_MAX - offset, "@rsc='%s']", rsc);
387 } else if (promoted_role_only == TRUE) {
388 rsc_role_substr = crm_strdup_printf("@role='%s'",
389 promoted_role_name());
390 offset += snprintf(first_half + offset, XPATH_MAX - offset,
391 "@role='%s']", promoted_role_name());
392 } else {
393 offset += snprintf(first_half + offset, XPATH_MAX - offset, "]");
394 }
395 }
396
397 if (node != NULL) {
398 if (rsc_role_substr != NULL) {
399 xpath_string = crm_strdup_printf("%s|//rsc_location[%s]/rule[expression[@attribute='#uname' and @value='%s']]%s",
400 first_half, rsc_role_substr, node, date_substr);
401 } else {
402 xpath_string = crm_strdup_printf("%s|//rsc_location/rule[expression[@attribute='#uname' and @value='%s']]%s",
403 first_half, node, date_substr);
404 }
405 } else {
406 xpath_string = crm_strdup_printf("%s%s", first_half, date_substr);
407 }
408
409 free(first_half);
410 free(date_substr);
411 free(rsc_role_substr);
412
413 return xpath_string;
414 }
415
416
417 int
418 cli_resource_clear_all_expired(xmlNode *root, cib_t *cib_conn, int cib_options,
419 const char *rsc, const char *node, gboolean promoted_role_only)
420 {
421 xmlXPathObject *xpathObj = NULL;
422 xmlNode *cib_constraints = NULL;
423 crm_time_t *now = crm_time_new(NULL);
424 int i;
425 int rc = pcmk_rc_ok;
426
427 cib_constraints = pcmk_find_cib_element(root, XML_CIB_TAG_CONSTRAINTS);
428 xpathObj = xpath_search(cib_constraints, "//" XML_CONS_TAG_RSC_LOCATION);
429
430 for (i = 0; i < numXpathResults(xpathObj); i++) {
431 xmlNode *constraint_node = getXpathResult(xpathObj, i);
432 xmlNode *date_expr_node = NULL;
433 crm_time_t *end = NULL;
434 char *xpath_string = NULL;
435
436 xpath_string = build_clear_xpath_string(constraint_node, rsc, node, promoted_role_only);
437 if (xpath_string == NULL) {
438 continue;
439 }
440
441 date_expr_node = get_xpath_object(xpath_string, constraint_node, LOG_DEBUG);
442 if (date_expr_node == NULL) {
443 free(xpath_string);
444 continue;
445 }
446
447
448
449
450 end = crm_time_new(crm_element_value(date_expr_node, "end"));
451
452 if (crm_time_compare(now, end) == 1) {
453 xmlNode *fragment = NULL;
454 xmlNode *location = NULL;
455
456 fragment = create_xml_node(NULL, XML_CIB_TAG_CONSTRAINTS);
457 location = create_xml_node(fragment, XML_CONS_TAG_RSC_LOCATION);
458 crm_xml_set_id(location, "%s", ID(constraint_node));
459 crm_log_xml_info(fragment, "Delete");
460
461 rc = cib_conn->cmds->remove(cib_conn, XML_CIB_TAG_CONSTRAINTS,
462 fragment, cib_options);
463 rc = pcmk_legacy2rc(rc);
464
465 if (rc != pcmk_rc_ok) {
466 free(xpath_string);
467 goto done;
468 }
469
470 free_xml(fragment);
471 }
472
473 crm_time_free(end);
474 free(xpath_string);
475 }
476
477 done:
478 freeXpathObject(xpathObj);
479 crm_time_free(now);
480 return rc;
481 }