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