This source file includes following definitions.
- prepend_node_info
- cli_resource_search
- find_resource_attr
- find_matching_attr_resources_recursive
- find_matching_attr_resources
- get_cib_rsc
- update_element_attribute
- resources_with_attr
- free_attr_update_data
- update_attribute
- cli_resource_update_attribute
- cli_resource_delete_attribute
- send_lrm_rsc_op
- rsc_fail_name
- clear_rsc_history
- clear_rsc_failures
- clear_rsc_fail_attrs
- cli_resource_delete
- cli_cleanup_all
- check_role
- check_managed
- check_locked
- node_is_unhealthy
- check_node_health
- cli_resource_check
- cli_resource_fail
- generate_resource_params
- resource_is_running_on
- get_active_resources
- dump_list
- display_list
- update_scheduler_input
- update_dataset
- max_rsc_stop_timeout
- wait_time_estimate
- cli_resource_restart
- action_is_pending
- actions_are_pending
- print_pending_actions
- wait_till_stable
- get_action
- set_agent_environment
- apply_overrides
- cli_resource_execute_from_params
- get_action_timeout
- cli_resource_execute
- cli_resource_move
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <stdbool.h>
13 #include <stdio.h>
14 #include <limits.h>
15
16 #include <glib.h>
17 #include <libxml/tree.h>
18 #include <libxml/xpath.h>
19
20 #include <crm/common/ipc_attrd_internal.h>
21 #include <crm/common/ipc_controld.h>
22 #include <crm/common/lists_internal.h>
23 #include <crm/services_internal.h>
24
25 #include <crm_resource.h>
26
27
28
29
30
31 struct rsc_node_info {
32 const pcmk_resource_t *rsc;
33
34
35 GList *list;
36 };
37
38
39
40
41
42
43
44
45
46
47
48 static void
49 prepend_node_info(gpointer data, gpointer user_data)
50 {
51 const pcmk_node_t *node = data;
52 struct rsc_node_info *rni = user_data;
53 node_info_t *ni = NULL;
54
55 pcmk__assert(rni->rsc != NULL);
56
57 ni = pcmk__assert_alloc(1, sizeof(node_info_t));
58 ni->node_name = node->priv->name;
59 ni->promoted = pcmk_is_set(rni->rsc->flags, pcmk__rsc_promotable)
60 && (rni->rsc->priv->fns->state(rni->rsc, true)
61 == pcmk_role_promoted);
62
63 rni->list = g_list_prepend(rni->list, ni);
64 }
65
66 GList *
67 cli_resource_search(const pcmk_resource_t *rsc, const char *requested_name)
68 {
69 const pcmk_resource_t *clone = NULL;
70 struct rsc_node_info rni = {
71 .rsc = rsc,
72 .list = NULL,
73 };
74
75 pcmk__assert(rsc != NULL);
76
77 if (pcmk__is_clone(rsc)) {
78 clone = rsc;
79
80 } else {
81 const pcmk_resource_t *parent = pe__const_top_resource(rsc, false);
82
83 if (pcmk__is_clone(parent)
84 && !pcmk_is_set(rsc->flags, pcmk__rsc_unique)
85 && (rsc->priv->history_id != NULL)
86 && pcmk__str_eq(requested_name, rsc->priv->history_id,
87 pcmk__str_none)
88 && !pcmk__str_eq(requested_name, rsc->id, pcmk__str_none)) {
89
90
91 clone = parent;
92 }
93 }
94
95 if (clone == NULL) {
96 g_list_foreach(rsc->priv->active_nodes, prepend_node_info, &rni);
97 return rni.list;
98 }
99
100 for (const GList *iter = clone->priv->children; iter != NULL;
101 iter = iter->next) {
102
103 const pcmk_resource_t *child = iter->data;
104
105 rni.rsc = child;
106 g_list_foreach(child->priv->active_nodes, prepend_node_info, &rni);
107 }
108 return rni.list;
109 }
110
111
112 static int
113 find_resource_attr(pcmk__output_t *out, cib_t * the_cib, const char *attr,
114 const char *rsc, const char *attr_set_type, const char *set_name,
115 const char *attr_id, const char *attr_name, xmlNode **result)
116 {
117 xmlNode *xml_search;
118 int rc = pcmk_rc_ok;
119 GString *xpath = NULL;
120 const char *xpath_base = NULL;
121
122 if (result) {
123 *result = NULL;
124 }
125
126 if(the_cib == NULL) {
127 return ENOTCONN;
128 }
129
130 xpath_base = pcmk_cib_xpath_for(PCMK_XE_RESOURCES);
131 if (xpath_base == NULL) {
132 crm_err(PCMK_XE_RESOURCES " CIB element not known (bug?)");
133 return ENOMSG;
134 }
135
136 xpath = g_string_sized_new(1024);
137 pcmk__g_strcat(xpath,
138 xpath_base, "//*[@" PCMK_XA_ID "=\"", rsc, "\"]", NULL);
139
140 if (attr_set_type != NULL) {
141 pcmk__g_strcat(xpath, "/", attr_set_type, NULL);
142 if (set_name != NULL) {
143 pcmk__g_strcat(xpath, "[@" PCMK_XA_ID "=\"", set_name, "\"]",
144 NULL);
145 }
146 }
147
148 g_string_append(xpath, "//" PCMK_XE_NVPAIR);
149
150 if (attr_id != NULL && attr_name!= NULL) {
151 pcmk__g_strcat(xpath,
152 "[@" PCMK_XA_ID "='", attr_id, "' "
153 "and @" PCMK_XA_NAME "='", attr_name, "']", NULL);
154
155 } else if (attr_id != NULL) {
156 pcmk__g_strcat(xpath, "[@" PCMK_XA_ID "='", attr_id, "']", NULL);
157
158 } else if (attr_name != NULL) {
159 pcmk__g_strcat(xpath, "[@" PCMK_XA_NAME "='", attr_name, "']", NULL);
160 }
161
162 rc = the_cib->cmds->query(the_cib, xpath->str, &xml_search,
163 cib_sync_call|cib_xpath);
164 rc = pcmk_legacy2rc(rc);
165
166 if (rc == pcmk_rc_ok) {
167 crm_log_xml_debug(xml_search, "Match");
168 if (xml_search->children != NULL) {
169 rc = ENOTUNIQ;
170 pcmk__warn_multiple_name_matches(out, xml_search, attr_name);
171 out->spacer(out);
172 }
173 }
174
175 if (result) {
176 *result = xml_search;
177 } else {
178 pcmk__xml_free(xml_search);
179 }
180
181 g_string_free(xpath, TRUE);
182 return rc;
183 }
184
185
186 static void
187 find_matching_attr_resources_recursive(pcmk__output_t *out,
188 GList **result,
189 pcmk_resource_t *rsc, const char * attr_set,
190 const char * attr_set_type, const char * attr_id,
191 const char * attr_name, cib_t * cib, int depth)
192 {
193 int rc = pcmk_rc_ok;
194 char *lookup_id = clone_strip(rsc->id);
195
196 for (GList *gIter = rsc->priv->children;
197 gIter != NULL; gIter = gIter->next) {
198
199 find_matching_attr_resources_recursive(out, result,
200 (pcmk_resource_t *) gIter->data,
201 attr_set, attr_set_type, attr_id,
202 attr_name, cib, depth+1);
203
204 if (pcmk__is_clone(rsc)) {
205 break;
206 }
207 }
208
209 rc = find_resource_attr(out, cib, PCMK_XA_ID, lookup_id, attr_set_type,
210 attr_set, attr_id, attr_name, NULL);
211
212
213 if((0 == depth) || (pcmk_rc_ok == rc)) {
214
215 *result = g_list_append(*result, rsc);
216 }
217
218 free(lookup_id);
219 }
220
221
222
223 static GList *
224 find_matching_attr_resources(pcmk__output_t *out, pcmk_resource_t *rsc,
225 const char * rsc_id, const char * attr_set,
226 const char * attr_set_type, const char * attr_id,
227 const char * attr_name, cib_t * cib, const char * cmd,
228 gboolean force)
229 {
230 int rc = pcmk_rc_ok;
231 char *lookup_id = NULL;
232 GList * result = NULL;
233
234
235
236
237 if(force == TRUE) {
238 return g_list_append(result, rsc);
239 }
240 if (pcmk__is_clone(rsc->priv->parent)) {
241 int rc = find_resource_attr(out, cib, PCMK_XA_ID, rsc_id, attr_set_type,
242 attr_set, attr_id, attr_name, NULL);
243
244 if(rc != pcmk_rc_ok) {
245 rsc = rsc->priv->parent;
246 out->info(out, "Performing %s of '%s' on '%s', the parent of '%s'",
247 cmd, attr_name, rsc->id, rsc_id);
248 }
249 return g_list_append(result, rsc);
250
251 } else if ((rsc->priv->parent == NULL)
252 && (rsc->priv->children != NULL) && pcmk__is_clone(rsc)) {
253
254 pcmk_resource_t *child = rsc->priv->children->data;
255
256 if (pcmk__is_primitive(child)) {
257 lookup_id = clone_strip(child->id);
258 rc = find_resource_attr(out, cib, PCMK_XA_ID, lookup_id,
259 attr_set_type, attr_set, attr_id, attr_name, NULL);
260
261 if(rc == pcmk_rc_ok) {
262 rsc = child;
263 out->info(out, "A value for '%s' already exists in child '%s', performing %s on that instead of '%s'",
264 attr_name, lookup_id, cmd, rsc_id);
265 }
266
267 free(lookup_id);
268 }
269 return g_list_append(result, rsc);
270 }
271
272 find_matching_attr_resources_recursive(out, &result, rsc, attr_set,
273 attr_set_type, attr_id, attr_name,
274 cib, 0);
275 return result;
276 }
277
278
279
280
281
282
283
284
285
286
287 static xmlNode *
288 get_cib_rsc(xmlNode *cib_xml, const pcmk_resource_t *rsc)
289 {
290 char *xpath = crm_strdup_printf("%s//*[@" PCMK_XA_ID "='%s']",
291 pcmk_cib_xpath_for(PCMK_XE_RESOURCES),
292 pcmk__xe_id(rsc->priv->xml));
293 xmlNode *rsc_xml = pcmk__xpath_find_one(cib_xml->doc, xpath, LOG_ERR);
294
295 free(xpath);
296 return rsc_xml;
297 }
298
299 static int
300 update_element_attribute(pcmk__output_t *out, pcmk_resource_t *rsc,
301 cib_t *cib, xmlNode *cib_xml_orig,
302 const char *attr_name, const char *attr_value)
303 {
304 int rc = pcmk_rc_ok;
305 xmlNode *rsc_xml = get_cib_rsc(cib_xml_orig, rsc);
306
307 if (rsc_xml == NULL) {
308 return ENXIO;
309 }
310
311 crm_xml_add(rsc_xml, attr_name, attr_value);
312
313 rc = cib->cmds->replace(cib, PCMK_XE_RESOURCES, rsc_xml, cib_sync_call);
314 rc = pcmk_legacy2rc(rc);
315 if (rc == pcmk_rc_ok) {
316 out->info(out, "Set attribute: " PCMK_XA_NAME "=%s value=%s",
317 attr_name, attr_value);
318 }
319
320 return rc;
321 }
322
323 static int
324 resources_with_attr(pcmk__output_t *out, cib_t *cib, pcmk_resource_t *rsc,
325 const char *requested_name, const char *attr_set,
326 const char *attr_set_type, const char *attr_id,
327 const char *attr_name, const char *top_id, gboolean force,
328 GList **resources)
329 {
330 if (pcmk__str_eq(attr_set_type, PCMK_XE_INSTANCE_ATTRIBUTES,
331 pcmk__str_casei)) {
332 if (!force) {
333 xmlNode *xml_search = NULL;
334 int rc = pcmk_rc_ok;
335
336 rc = find_resource_attr(out, cib, PCMK_XA_ID, top_id,
337 PCMK_XE_META_ATTRIBUTES, attr_set, attr_id,
338 attr_name, &xml_search);
339
340 if (rc == pcmk_rc_ok || rc == ENOTUNIQ) {
341 char *found_attr_id = NULL;
342
343 found_attr_id = crm_element_value_copy(xml_search, PCMK_XA_ID);
344
345 if (!out->is_quiet(out)) {
346 out->err(out,
347 "WARNING: There is already a meta attribute "
348 "for '%s' called '%s' (id=%s)",
349 top_id, attr_name, found_attr_id);
350 out->err(out,
351 " Delete '%s' first or use the force option "
352 "to override", found_attr_id);
353 }
354
355 free(found_attr_id);
356 pcmk__xml_free(xml_search);
357 return ENOTUNIQ;
358 }
359
360 pcmk__xml_free(xml_search);
361 }
362
363 *resources = g_list_append(*resources, rsc);
364
365 } else {
366 *resources = find_matching_attr_resources(out, rsc, requested_name,
367 attr_set, attr_set_type,
368 attr_id, attr_name, cib,
369 "update", force);
370 }
371
372
373
374
375 if ((attr_set != NULL) || (attr_id != NULL)) {
376 GList *last = g_list_last(*resources);
377
378 *resources = g_list_remove_link(*resources, last);
379 g_list_free(*resources);
380 *resources = last;
381 }
382
383 return pcmk_rc_ok;
384 }
385
386 static void
387 free_attr_update_data(gpointer data)
388 {
389 attr_update_data_t *ud = data;
390
391 if (ud == NULL) {
392 return;
393 }
394
395 free(ud->attr_set_type);
396 free(ud->attr_set_id);
397 free(ud->attr_name);
398 free(ud->attr_value);
399 free(ud->given_rsc_id);
400 free(ud->found_attr_id);
401 free(ud);
402 }
403
404 static int
405 update_attribute(pcmk_resource_t *rsc, const char *requested_name,
406 const char *attr_set, const char *attr_set_type,
407 const char *attr_id, const char *attr_name,
408 const char *attr_value, gboolean recursive, cib_t *cib,
409 xmlNode *cib_xml_orig, gboolean force, GList **results)
410 {
411 pcmk__output_t *out = rsc->priv->scheduler->priv->out;
412 int rc = pcmk_rc_ok;
413
414 GList *resources = NULL;
415 const char *top_id = pe__const_top_resource(rsc, false)->id;
416
417 if ((attr_id == NULL) && !force) {
418 find_resource_attr(out, cib, PCMK_XA_ID, top_id, NULL, NULL, NULL,
419 attr_name, NULL);
420 }
421
422 rc = resources_with_attr(out, cib, rsc, requested_name, attr_set, attr_set_type,
423 attr_id, attr_name, top_id, force, &resources);
424
425 if (rc != pcmk_rc_ok) {
426 return rc;
427 }
428
429 for (GList *iter = resources; iter != NULL; iter = iter->next) {
430
431 char *lookup_id = NULL;
432 char *local_attr_set = NULL;
433 char *found_attr_id = NULL;
434 const char *rsc_attr_id = attr_id;
435 const char *rsc_attr_set = attr_set;
436
437 xmlNode *rsc_xml = NULL;
438 xmlNode *xml_top = NULL;
439 xmlNode *xml_obj = NULL;
440 xmlNode *xml_search = NULL;
441
442 rsc = (pcmk_resource_t *) iter->data;
443
444 lookup_id = clone_strip(rsc->id);
445 rc = find_resource_attr(out, cib, PCMK_XA_ID, lookup_id, attr_set_type,
446 attr_set, attr_id, attr_name, &xml_search);
447
448 switch (rc) {
449 case pcmk_rc_ok:
450 found_attr_id = crm_element_value_copy(xml_search, PCMK_XA_ID);
451 crm_debug("Found a match for " PCMK_XA_NAME "='%s': "
452 PCMK_XA_ID "='%s'", attr_name, found_attr_id);
453 rsc_attr_id = found_attr_id;
454 break;
455
456 case ENXIO:
457 if (rsc_attr_set == NULL) {
458 local_attr_set = crm_strdup_printf("%s-%s", lookup_id,
459 attr_set_type);
460 rsc_attr_set = local_attr_set;
461 }
462 if (rsc_attr_id == NULL) {
463 found_attr_id = crm_strdup_printf("%s-%s",
464 rsc_attr_set, attr_name);
465 rsc_attr_id = found_attr_id;
466 }
467
468 rsc_xml = get_cib_rsc(cib_xml_orig, rsc);
469 if (rsc_xml == NULL) {
470
471
472
473
474
475 free(lookup_id);
476 free(found_attr_id);
477 pcmk__xml_free(xml_search);
478 g_list_free(resources);
479 return ENXIO;
480 }
481
482 xml_top = pcmk__xe_create(NULL, (const char *) rsc_xml->name);
483 crm_xml_add(xml_top, PCMK_XA_ID, lookup_id);
484
485 xml_obj = pcmk__xe_create(xml_top, attr_set_type);
486 crm_xml_add(xml_obj, PCMK_XA_ID, rsc_attr_set);
487 break;
488
489 default:
490 free(lookup_id);
491 free(found_attr_id);
492 pcmk__xml_free(xml_search);
493 g_list_free(resources);
494 return rc;
495 }
496
497 xml_obj = crm_create_nvpair_xml(xml_obj, rsc_attr_id, attr_name,
498 attr_value);
499 if (xml_top == NULL) {
500 xml_top = xml_obj;
501 }
502
503 crm_log_xml_debug(xml_top, "Update");
504
505 rc = cib->cmds->modify(cib, PCMK_XE_RESOURCES, xml_top, cib_sync_call);
506 rc = pcmk_legacy2rc(rc);
507 if (rc == pcmk_rc_ok) {
508 attr_update_data_t *ud = pcmk__assert_alloc(1, sizeof(attr_update_data_t));
509
510 if (attr_set_type == NULL) {
511 attr_set_type = (const char *) xml_search->parent->name;
512 }
513
514 if (rsc_attr_set == NULL) {
515 rsc_attr_set = crm_element_value(xml_search->parent, PCMK_XA_ID);
516 }
517
518 ud->attr_set_type = pcmk__str_copy(attr_set_type);
519 ud->attr_set_id = pcmk__str_copy(rsc_attr_set);
520 ud->attr_name = pcmk__str_copy(attr_name);
521 ud->attr_value = pcmk__str_copy(attr_value);
522 ud->given_rsc_id = pcmk__str_copy(lookup_id);
523 ud->found_attr_id = pcmk__str_copy(found_attr_id);
524 ud->rsc = rsc;
525
526 *results = g_list_append(*results, ud);
527 }
528
529 pcmk__xml_free(xml_top);
530 pcmk__xml_free(xml_search);
531
532 free(lookup_id);
533 free(found_attr_id);
534 free(local_attr_set);
535
536 if (recursive
537 && pcmk__str_eq(attr_set_type, PCMK_XE_META_ATTRIBUTES,
538 pcmk__str_casei)) {
539
540
541
542
543
544 pcmk__set_rsc_flags(rsc, pcmk__rsc_detect_loop);
545 for (GList *lpc = rsc->priv->with_this_colocations;
546 lpc != NULL; lpc = lpc->next) {
547 pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
548
549 crm_debug("Checking %s %d", cons->id, cons->score);
550
551 if (pcmk_is_set(cons->dependent->flags, pcmk__rsc_detect_loop)
552 || (cons->score <= 0)) {
553 continue;
554 }
555
556 crm_debug("Setting %s=%s for dependent resource %s",
557 attr_name, attr_value, cons->dependent->id);
558 update_attribute(cons->dependent, cons->dependent->id, NULL,
559 attr_set_type, NULL, attr_name, attr_value,
560 recursive, cib, cib_xml_orig, force, results);
561 }
562 }
563 }
564
565 g_list_free(resources);
566 return rc;
567 }
568
569
570 int
571 cli_resource_update_attribute(pcmk_resource_t *rsc, const char *requested_name,
572 const char *attr_set, const char *attr_set_type,
573 const char *attr_id, const char *attr_name,
574 const char *attr_value, gboolean recursive,
575 cib_t *cib, xmlNode *cib_xml_orig, gboolean force)
576 {
577 static bool need_init = true;
578 int rc = pcmk_rc_ok;
579
580 GList *results = NULL;
581 pcmk__output_t *out = rsc->priv->scheduler->priv->out;
582
583 pcmk__assert(cib_xml_orig != NULL);
584
585
586
587
588 if (pcmk__str_eq(attr_set_type, ATTR_SET_ELEMENT, pcmk__str_none)) {
589 return update_element_attribute(out, rsc, cib, cib_xml_orig, attr_name,
590 attr_value);
591 }
592
593
594 if (need_init) {
595 need_init = false;
596 pcmk__unpack_constraints(rsc->priv->scheduler);
597 pe__clear_resource_flags_on_all(rsc->priv->scheduler,
598 pcmk__rsc_detect_loop);
599 }
600
601 rc = update_attribute(rsc, requested_name, attr_set, attr_set_type,
602 attr_id, attr_name, attr_value, recursive, cib,
603 cib_xml_orig, force, &results);
604
605 if (rc == pcmk_rc_ok) {
606 if (results == NULL) {
607 return rc;
608 }
609
610 out->message(out, "attribute-changed-list", results);
611 g_list_free_full(results, free_attr_update_data);
612 }
613
614 return rc;
615 }
616
617
618 int
619 cli_resource_delete_attribute(pcmk_resource_t *rsc, const char *requested_name,
620 const char *attr_set, const char *attr_set_type,
621 const char *attr_id, const char *attr_name,
622 cib_t *cib, xmlNode *cib_xml_orig, gboolean force)
623 {
624 pcmk__output_t *out = rsc->priv->scheduler->priv->out;
625 int rc = pcmk_rc_ok;
626 GList *resources = NULL;
627
628 pcmk__assert((cib != NULL) && (cib_xml_orig != NULL));
629
630 if ((attr_id == NULL) && !force) {
631 find_resource_attr(out, cib, PCMK_XA_ID,
632 pe__const_top_resource(rsc, false)->id, NULL,
633 NULL, NULL, attr_name, NULL);
634 }
635
636 if (pcmk__str_eq(attr_set_type, ATTR_SET_ELEMENT, pcmk__str_none)) {
637 xmlNode *rsc_xml = get_cib_rsc(cib_xml_orig, rsc);
638
639 if (rsc_xml == NULL) {
640 return ENXIO;
641 }
642
643 pcmk__xe_remove_attr(rsc_xml, attr_name);
644 rc = cib->cmds->replace(cib, PCMK_XE_RESOURCES, rsc_xml, cib_sync_call);
645 rc = pcmk_legacy2rc(rc);
646 if (rc == pcmk_rc_ok) {
647 out->info(out, "Deleted attribute: %s", attr_name);
648 }
649 return rc;
650 }
651
652 if (pcmk__str_eq(attr_set_type, PCMK_XE_META_ATTRIBUTES, pcmk__str_none)) {
653 resources = find_matching_attr_resources(out, rsc, requested_name,
654 attr_set, attr_set_type,
655 attr_id, attr_name, cib,
656 "delete", force);
657 } else {
658 resources = g_list_append(resources, rsc);
659 }
660
661 for (GList *iter = resources; iter != NULL; iter = iter->next) {
662 char *lookup_id = NULL;
663 xmlNode *xml_obj = NULL;
664 xmlNode *xml_search = NULL;
665 char *found_attr_id = NULL;
666 const char *rsc_attr_id = attr_id;
667
668 rsc = (pcmk_resource_t *) iter->data;
669
670
671
672
673
674 lookup_id = clone_strip(rsc->id);
675 rc = find_resource_attr(out, cib, PCMK_XA_ID, lookup_id, attr_set_type,
676 attr_set, attr_id, attr_name, &xml_search);
677 switch (rc) {
678 case pcmk_rc_ok:
679 found_attr_id = crm_element_value_copy(xml_search, PCMK_XA_ID);
680 pcmk__xml_free(xml_search);
681 break;
682
683 case ENXIO:
684 free(lookup_id);
685 pcmk__xml_free(xml_search);
686 continue;
687
688 default:
689 free(lookup_id);
690 pcmk__xml_free(xml_search);
691 g_list_free(resources);
692 return rc;
693 }
694
695 if (rsc_attr_id == NULL) {
696 rsc_attr_id = found_attr_id;
697 }
698
699 xml_obj = crm_create_nvpair_xml(NULL, rsc_attr_id, attr_name, NULL);
700 crm_log_xml_debug(xml_obj, "Delete");
701
702 rc = cib->cmds->remove(cib, PCMK_XE_RESOURCES, xml_obj, cib_sync_call);
703 rc = pcmk_legacy2rc(rc);
704
705 if (rc == pcmk_rc_ok) {
706 out->info(out, "Deleted '%s' option: " PCMK_XA_ID "=%s%s%s%s%s",
707 lookup_id, found_attr_id,
708 ((attr_set == NULL)? "" : " set="),
709 pcmk__s(attr_set, ""),
710 ((attr_name == NULL)? "" : " " PCMK_XA_NAME "="),
711 pcmk__s(attr_name, ""));
712 }
713
714 free(lookup_id);
715 pcmk__xml_free(xml_obj);
716 free(found_attr_id);
717 }
718
719 g_list_free(resources);
720 return rc;
721 }
722
723
724 static int
725 send_lrm_rsc_op(pcmk_ipc_api_t *controld_api, bool do_fail_resource,
726 pcmk_resource_t *rsc, const char *rsc_id,
727 const pcmk_node_t *node)
728 {
729 pcmk__output_t *out = NULL;
730 const char *rsc_api_id = NULL;
731 const char *rsc_long_id = NULL;
732 const char *rsc_class = NULL;
733 const char *rsc_provider = NULL;
734 const char *rsc_type = NULL;
735 const char *router_node = NULL;
736 bool cib_only = false;
737
738 pcmk__assert((rsc != NULL) && (rsc_id != NULL) && (node != NULL));
739
740 out = rsc->priv->scheduler->priv->out;
741
742 if (!pcmk__is_primitive(rsc)) {
743 out->err(out, "We can only process primitive resources, not %s",
744 rsc_id);
745 return EINVAL;
746 }
747
748 rsc_class = crm_element_value(rsc->priv->xml, PCMK_XA_CLASS);
749 rsc_provider = crm_element_value(rsc->priv->xml, PCMK_XA_PROVIDER);
750 rsc_type = crm_element_value(rsc->priv->xml, PCMK_XA_TYPE);
751 if ((rsc_class == NULL) || (rsc_type == NULL)) {
752 out->err(out, "Resource %s does not have a class and type", rsc_id);
753 return EINVAL;
754 }
755
756 router_node = node->priv->name;
757
758 if (!node->details->online) {
759 if (do_fail_resource) {
760 out->err(out, "Node %s is not online", pcmk__node_name(node));
761 return ENOTCONN;
762 }
763 cib_only = true;
764
765 } else if (pcmk__is_pacemaker_remote_node(node)) {
766 const pcmk_node_t *conn_host = pcmk__current_node(node->priv->remote);
767
768 if (conn_host == NULL) {
769 out->err(out,
770 "No cluster connection to Pacemaker Remote node %s "
771 "detected",
772 pcmk__node_name(node));
773 return ENOTCONN;
774 }
775 router_node = conn_host->priv->name;
776 }
777
778 if (rsc->priv->history_id != NULL) {
779 rsc_api_id = rsc->priv->history_id;
780 rsc_long_id = rsc->id;
781 } else {
782 rsc_api_id = rsc->id;
783 }
784
785 if (do_fail_resource) {
786 return pcmk_controld_api_fail(controld_api, node->priv->name,
787 router_node, rsc_api_id, rsc_long_id,
788 rsc_class, rsc_provider, rsc_type);
789 }
790 return pcmk_controld_api_refresh(controld_api, node->priv->name,
791 router_node, rsc_api_id, rsc_long_id,
792 rsc_class, rsc_provider, rsc_type,
793 cib_only);
794 }
795
796
797
798
799
800
801
802
803
804
805 static inline char *
806 rsc_fail_name(const pcmk_resource_t *rsc)
807 {
808 const char *name = pcmk__s(rsc->priv->history_id, rsc->id);
809
810 if (pcmk_is_set(rsc->flags, pcmk__rsc_unique)) {
811 return strdup(name);
812 }
813 return clone_strip(name);
814 }
815
816
817 static int
818 clear_rsc_history(pcmk_ipc_api_t *controld_api, pcmk_resource_t *rsc,
819 const char *rsc_id, const pcmk_node_t *node)
820 {
821 int rc = pcmk_rc_ok;
822
823 pcmk__assert((rsc != NULL) && (node != NULL));
824
825
826
827
828
829
830 rc = send_lrm_rsc_op(controld_api, false, rsc, rsc_id, node);
831 if (rc != pcmk_rc_ok) {
832 return rc;
833 }
834
835 crm_trace("Processing %d mainloop inputs",
836 pcmk_controld_api_replies_expected(controld_api));
837 while (g_main_context_iteration(NULL, FALSE)) {
838 crm_trace("Processed mainloop input, %d still remaining",
839 pcmk_controld_api_replies_expected(controld_api));
840 }
841 return rc;
842 }
843
844
845 static int
846 clear_rsc_failures(pcmk__output_t *out, pcmk_ipc_api_t *controld_api,
847 pcmk_node_t *node, const char *rsc_id, const char *operation,
848 const char *interval_spec)
849 {
850 int rc = pcmk_rc_ok;
851 pcmk_scheduler_t *scheduler = NULL;
852 const char *failed_value = NULL;
853 const char *failed_id = NULL;
854 char *interval_ms_s = NULL;
855 GHashTable *rscs = NULL;
856 GHashTableIter iter;
857
858 pcmk__assert(node != NULL);
859
860 scheduler = node->priv->scheduler;
861
862
863
864
865
866 rscs = pcmk__strkey_table(NULL, NULL);
867
868
869 if (operation) {
870 guint interval_ms = 0U;
871
872 pcmk_parse_interval_spec(interval_spec, &interval_ms);
873 interval_ms_s = crm_strdup_printf("%u", interval_ms);
874 }
875
876 for (xmlNode *xml_op = pcmk__xe_first_child(scheduler->priv->failed, NULL,
877 NULL, NULL);
878 xml_op != NULL; xml_op = pcmk__xe_next(xml_op, NULL)) {
879
880 failed_id = crm_element_value(xml_op, PCMK__XA_RSC_ID);
881 if (failed_id == NULL) {
882
883 continue;
884 }
885
886
887 if (rsc_id) {
888 pcmk_resource_t *fail_rsc = NULL;
889
890 fail_rsc = pe_find_resource_with_flags(scheduler->priv->resources,
891 failed_id,
892 pcmk_rsc_match_history
893 |pcmk_rsc_match_anon_basename);
894 if ((fail_rsc == NULL)
895 || !pcmk__str_eq(rsc_id, fail_rsc->id, pcmk__str_none)) {
896 continue;
897 }
898 }
899
900
901 failed_value = crm_element_value(xml_op, PCMK_XA_UNAME);
902 if (!pcmk__str_eq(node->priv->name, failed_value, pcmk__str_casei)) {
903 continue;
904 }
905
906
907 if (operation) {
908 failed_value = crm_element_value(xml_op, PCMK_XA_OPERATION);
909 if (!pcmk__str_eq(operation, failed_value, pcmk__str_casei)) {
910 continue;
911 }
912
913
914 failed_value = crm_element_value(xml_op, PCMK_META_INTERVAL);
915 if (!pcmk__str_eq(interval_ms_s, failed_value, pcmk__str_casei)) {
916 continue;
917 }
918 }
919
920 g_hash_table_add(rscs, (gpointer) failed_id);
921 }
922
923 free(interval_ms_s);
924
925 g_hash_table_iter_init(&iter, rscs);
926 while (g_hash_table_iter_next(&iter, (gpointer *) &failed_id, NULL)) {
927 pcmk_resource_t *rsc = NULL;
928
929 crm_debug("Erasing failures of %s on %s",
930 failed_id, pcmk__node_name(node));
931
932 rsc = pe_find_resource(scheduler->priv->resources, failed_id);
933 if (rsc == NULL) {
934 out->err(out, "Resource %s not found", failed_id);
935 return ENXIO;
936 }
937
938 rc = clear_rsc_history(controld_api, rsc, failed_id, node);
939 if (rc != pcmk_rc_ok) {
940 return rc;
941 }
942 }
943 g_hash_table_destroy(rscs);
944 return rc;
945 }
946
947
948 static int
949 clear_rsc_fail_attrs(const pcmk_resource_t *rsc, const char *operation,
950 const char *interval_spec, const pcmk_node_t *node)
951 {
952 int rc = pcmk_rc_ok;
953 int attr_options = pcmk__node_attr_none;
954 char *rsc_name = rsc_fail_name(rsc);
955
956 if (pcmk__is_pacemaker_remote_node(node)) {
957 attr_options |= pcmk__node_attr_remote;
958 }
959
960 rc = pcmk__attrd_api_clear_failures(NULL, node->priv->name, rsc_name,
961 operation, interval_spec, NULL,
962 attr_options);
963 free(rsc_name);
964 return rc;
965 }
966
967
968 int
969 cli_resource_delete(pcmk_ipc_api_t *controld_api, pcmk_resource_t *rsc,
970 pcmk_node_t *node, const char *operation,
971 const char *interval_spec, bool just_failures, bool force)
972 {
973 pcmk_scheduler_t *scheduler = NULL;
974 pcmk__output_t *out = NULL;
975 int rc = pcmk_rc_ok;
976
977 pcmk__assert(rsc != NULL);
978
979 scheduler = rsc->priv->scheduler;
980 out = scheduler->priv->out;
981
982 if (rsc->priv->children != NULL) {
983 for (GList *iter = rsc->priv->children; iter != NULL;
984 iter = iter->next) {
985
986 pcmk_resource_t *child = iter->data;
987
988 rc = cli_resource_delete(controld_api, child, node, operation,
989 interval_spec, just_failures, force);
990 if (rc != pcmk_rc_ok) {
991 return rc;
992 }
993 }
994 return pcmk_rc_ok;
995 }
996
997 if (node == NULL) {
998 GList *nodes = g_hash_table_get_values(rsc->priv->probed_nodes);
999
1000 if (nodes == NULL) {
1001 if (force) {
1002 nodes = g_list_copy(scheduler->nodes);
1003
1004 } else if (pcmk_is_set(rsc->flags, pcmk__rsc_exclusive_probes)) {
1005 GHashTableIter iter;
1006
1007 g_hash_table_iter_init(&iter, rsc->priv->allowed_nodes);
1008 while (g_hash_table_iter_next(&iter, NULL,
1009 (gpointer *) &node)) {
1010 if ((node != NULL) && (node->assign->score >= 0)) {
1011 nodes = g_list_prepend(nodes, (gpointer *) node);
1012 }
1013 }
1014
1015 } else {
1016 nodes = g_hash_table_get_values(rsc->priv->allowed_nodes);
1017 }
1018 }
1019
1020 for (GList *iter = nodes; iter != NULL; iter = iter->next) {
1021 node = (pcmk_node_t *) iter->data;
1022
1023 if (!node->details->online) {
1024 continue;
1025 }
1026
1027 rc = cli_resource_delete(controld_api, rsc, node, operation,
1028 interval_spec, just_failures, force);
1029 if (rc != pcmk_rc_ok) {
1030 break;
1031 }
1032 }
1033
1034 g_list_free(nodes);
1035 return rc;
1036 }
1037
1038 if (!pcmk_is_set(node->priv->flags, pcmk__node_probes_allowed)) {
1039 out->err(out,
1040 "Unable to clean up %s because resource discovery disabled on "
1041 "%s",
1042 rsc->id, pcmk__node_name(node));
1043 return EOPNOTSUPP;
1044 }
1045
1046 if (controld_api == NULL) {
1047 out->err(out, "Dry run: skipping clean-up of %s on %s due to CIB_file",
1048 rsc->id, pcmk__node_name(node));
1049 return pcmk_rc_ok;
1050 }
1051
1052 rc = clear_rsc_fail_attrs(rsc, operation, interval_spec, node);
1053 if (rc != pcmk_rc_ok) {
1054 out->err(out, "Unable to clean up %s failures on %s: %s",
1055 rsc->id, pcmk__node_name(node), pcmk_rc_str(rc));
1056 return rc;
1057 }
1058
1059 if (just_failures) {
1060 rc = clear_rsc_failures(out, controld_api, node, rsc->id, operation,
1061 interval_spec);
1062 } else {
1063 rc = clear_rsc_history(controld_api, rsc, rsc->id, node);
1064 }
1065
1066 if (rc != pcmk_rc_ok) {
1067 out->err(out,
1068 "Cleaned %s failures on %s, but unable to clean history: %s",
1069 rsc->id, pcmk__node_name(node), pcmk_rc_str(rc));
1070 } else {
1071 out->info(out, "Cleaned up %s on %s", rsc->id, pcmk__node_name(node));
1072 }
1073 return rc;
1074 }
1075
1076
1077 int
1078 cli_cleanup_all(pcmk_ipc_api_t *controld_api, pcmk_node_t *node,
1079 const char *operation, const char *interval_spec,
1080 pcmk_scheduler_t *scheduler)
1081 {
1082 pcmk__output_t *out = NULL;
1083 int rc = pcmk_rc_ok;
1084 int attr_options = pcmk__node_attr_none;
1085 const char *node_name = NULL;
1086 const char *log_node_name = "all nodes";
1087
1088 pcmk__assert(scheduler != NULL);
1089
1090 out = scheduler->priv->out;
1091
1092 if (node != NULL) {
1093 node_name = node->priv->name;
1094 log_node_name = pcmk__node_name(node);
1095 }
1096
1097 if (controld_api == NULL) {
1098 out->info(out, "Dry run: skipping clean-up of %s due to CIB_file",
1099 log_node_name);
1100 return rc;
1101 }
1102
1103 if (pcmk__is_pacemaker_remote_node(node)) {
1104 pcmk__set_node_attr_flags(attr_options, pcmk__node_attr_remote);
1105 }
1106
1107 rc = pcmk__attrd_api_clear_failures(NULL, node_name, NULL, operation,
1108 interval_spec, NULL, attr_options);
1109 if (rc != pcmk_rc_ok) {
1110 out->err(out, "Unable to clean up all failures on %s: %s",
1111 log_node_name, pcmk_rc_str(rc));
1112 return rc;
1113 }
1114
1115 if (node != NULL) {
1116 rc = clear_rsc_failures(out, controld_api, node, NULL, operation,
1117 interval_spec);
1118
1119 } else {
1120 for (GList *iter = scheduler->nodes; iter; iter = iter->next) {
1121 pcmk_node_t *sched_node = iter->data;
1122
1123 rc = clear_rsc_failures(out, controld_api, sched_node, NULL,
1124 operation, interval_spec);
1125 if (rc != pcmk_rc_ok) {
1126 break;
1127 }
1128 }
1129 }
1130
1131 if (rc == pcmk_rc_ok) {
1132 out->info(out, "Cleaned up all resources on %s", log_node_name);
1133 } else {
1134
1135 out->err(out,
1136 "Cleaned all resource failures on %s, but unable to clean "
1137 "history: %s",
1138 log_node_name, pcmk_rc_str(rc));
1139 }
1140 return rc;
1141 }
1142
1143 static void
1144 check_role(resource_checks_t *checks)
1145 {
1146 const char *role_s = g_hash_table_lookup(checks->rsc->priv->meta,
1147 PCMK_META_TARGET_ROLE);
1148
1149 if (role_s == NULL) {
1150 return;
1151 }
1152 switch (pcmk_parse_role(role_s)) {
1153 case pcmk_role_stopped:
1154 checks->flags |= rsc_remain_stopped;
1155 break;
1156
1157 case pcmk_role_unpromoted:
1158 if (pcmk_is_set(pe__const_top_resource(checks->rsc, false)->flags,
1159 pcmk__rsc_promotable)) {
1160 checks->flags |= rsc_unpromotable;
1161 }
1162 break;
1163
1164 default:
1165 break;
1166 }
1167 }
1168
1169 static void
1170 check_managed(resource_checks_t *checks)
1171 {
1172 const char *managed_s = g_hash_table_lookup(checks->rsc->priv->meta,
1173 PCMK_META_IS_MANAGED);
1174
1175 if ((managed_s != NULL) && !crm_is_true(managed_s)) {
1176 checks->flags |= rsc_unmanaged;
1177 }
1178 }
1179
1180 static void
1181 check_locked(resource_checks_t *checks)
1182 {
1183 const pcmk_node_t *lock_node = checks->rsc->priv->lock_node;
1184
1185 if (lock_node != NULL) {
1186 checks->flags |= rsc_locked;
1187 checks->lock_node = lock_node->priv->name;
1188 }
1189 }
1190
1191 static bool
1192 node_is_unhealthy(pcmk_node_t *node)
1193 {
1194 switch (pe__health_strategy(node->priv->scheduler)) {
1195 case pcmk__health_strategy_none:
1196 break;
1197
1198 case pcmk__health_strategy_no_red:
1199 if (pe__node_health(node) < 0) {
1200 return true;
1201 }
1202 break;
1203
1204 case pcmk__health_strategy_only_green:
1205 if (pe__node_health(node) <= 0) {
1206 return true;
1207 }
1208 break;
1209
1210 case pcmk__health_strategy_progressive:
1211 case pcmk__health_strategy_custom:
1212
1213
1214
1215
1216 break;
1217 }
1218 return false;
1219 }
1220
1221 static void
1222 check_node_health(resource_checks_t *checks, pcmk_node_t *node)
1223 {
1224 if (node == NULL) {
1225 GHashTableIter iter;
1226 bool allowed = false;
1227 bool all_nodes_unhealthy = true;
1228
1229 g_hash_table_iter_init(&iter, checks->rsc->priv->allowed_nodes);
1230 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
1231 allowed = true;
1232 if (!node_is_unhealthy(node)) {
1233 all_nodes_unhealthy = false;
1234 break;
1235 }
1236 }
1237 if (allowed && all_nodes_unhealthy) {
1238 checks->flags |= rsc_node_health;
1239 }
1240
1241 } else if (node_is_unhealthy(node)) {
1242 checks->flags |= rsc_node_health;
1243 }
1244 }
1245
1246
1247
1248
1249 int
1250 cli_resource_check(pcmk__output_t *out, pcmk_resource_t *rsc, pcmk_node_t *node)
1251 {
1252 resource_checks_t checks = { .rsc = rsc };
1253
1254 check_role(&checks);
1255 check_managed(&checks);
1256 check_locked(&checks);
1257 check_node_health(&checks, node);
1258
1259 return out->message(out, "resource-check-list", &checks);
1260 }
1261
1262
1263 int
1264 cli_resource_fail(pcmk_ipc_api_t *controld_api, pcmk_resource_t *rsc,
1265 const char *rsc_id, const pcmk_node_t *node)
1266 {
1267 pcmk__assert((rsc != NULL) && (rsc_id != NULL) && (node != NULL));
1268
1269 if (controld_api == NULL) {
1270 pcmk__output_t *out = rsc->priv->scheduler->priv->out;
1271
1272 out->err(out, "Dry run: skipping fail of %s on %s due to CIB_file",
1273 rsc_id, pcmk__node_name(node));
1274 return pcmk_rc_ok;
1275 }
1276 crm_notice("Failing %s on %s", rsc_id, pcmk__node_name(node));
1277 return send_lrm_rsc_op(controld_api, true, rsc, rsc_id, node);
1278 }
1279
1280 static GHashTable *
1281 generate_resource_params(pcmk_resource_t *rsc)
1282 {
1283 GHashTable *params = NULL;
1284 GHashTable *meta = NULL;
1285 GHashTable *combined = NULL;
1286 GHashTableIter iter;
1287 char *key = NULL;
1288 char *value = NULL;
1289
1290 combined = pcmk__strkey_table(free, free);
1291
1292 params = pe_rsc_params(rsc, NULL, rsc->priv->scheduler);
1293 if (params != NULL) {
1294 g_hash_table_iter_init(&iter, params);
1295 while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
1296 pcmk__insert_dup(combined, key, value);
1297 }
1298 }
1299
1300 meta = pcmk__strkey_table(free, free);
1301 get_meta_attributes(meta, rsc, NULL, rsc->priv->scheduler);
1302 if (meta != NULL) {
1303 g_hash_table_iter_init(&iter, meta);
1304 while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
1305 char *crm_name = crm_meta_name(key);
1306
1307 g_hash_table_insert(combined, crm_name, strdup(value));
1308 }
1309 g_hash_table_destroy(meta);
1310 }
1311
1312 return combined;
1313 }
1314
1315 bool resource_is_running_on(pcmk_resource_t *rsc, const char *host)
1316 {
1317 bool found = true;
1318 GList *hIter = NULL;
1319 GList *hosts = NULL;
1320
1321 if (rsc == NULL) {
1322 return false;
1323 }
1324
1325 rsc->priv->fns->location(rsc, &hosts, pcmk__rsc_node_current);
1326 for (hIter = hosts; host != NULL && hIter != NULL; hIter = hIter->next) {
1327 pcmk_node_t *node = (pcmk_node_t *) hIter->data;
1328
1329 if (pcmk__strcase_any_of(host, node->priv->name, node->priv->id,
1330 NULL)) {
1331 crm_trace("Resource %s is running on %s\n", rsc->id, host);
1332 goto done;
1333 }
1334 }
1335
1336 if (host != NULL) {
1337 crm_trace("Resource %s is not running on: %s\n", rsc->id, host);
1338 found = false;
1339
1340 } else if(host == NULL && hosts == NULL) {
1341 crm_trace("Resource %s is not running\n", rsc->id);
1342 found = false;
1343 }
1344
1345 done:
1346 g_list_free(hosts);
1347 return found;
1348 }
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359 static GList *
1360 get_active_resources(const char *host, GList *rsc_list)
1361 {
1362 GList *rIter = NULL;
1363 GList *active = NULL;
1364
1365 for (rIter = rsc_list; rIter != NULL; rIter = rIter->next) {
1366 pcmk_resource_t *rsc = (pcmk_resource_t *) rIter->data;
1367
1368
1369
1370
1371
1372 if (pcmk__is_group(rsc)) {
1373 GList *member_active = NULL;
1374
1375 member_active = get_active_resources(host, rsc->priv->children);
1376 active = g_list_concat(active, member_active);
1377 } else if (resource_is_running_on(rsc, host)) {
1378 active = g_list_append(active, strdup(rsc->id));
1379 }
1380 }
1381 return active;
1382 }
1383
1384 static void dump_list(GList *items, const char *tag)
1385 {
1386 int lpc = 0;
1387 GList *item = NULL;
1388
1389 for (item = items; item != NULL; item = item->next) {
1390 crm_trace("%s[%d]: %s", tag, lpc, (char*)item->data);
1391 lpc++;
1392 }
1393 }
1394
1395 static void display_list(pcmk__output_t *out, GList *items, const char *tag)
1396 {
1397 GList *item = NULL;
1398
1399 for (item = items; item != NULL; item = item->next) {
1400 out->info(out, "%s%s", tag, (const char *)item->data);
1401 }
1402 }
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418 int
1419 update_scheduler_input(pcmk__output_t *out, pcmk_scheduler_t *scheduler,
1420 cib_t *cib, xmlNode **cib_xml_orig)
1421 {
1422 xmlNode *queried_xml = NULL;
1423 xmlNode *updated_xml = NULL;
1424 int rc = pcmk_rc_ok;
1425
1426 pcmk__assert((out != NULL) && (scheduler != NULL)
1427 && (scheduler->input == NULL) && (scheduler->priv->now == NULL)
1428 && (cib != NULL)
1429 && ((cib_xml_orig == NULL) || (*cib_xml_orig == NULL)));
1430
1431 rc = cib->cmds->query(cib, NULL, &queried_xml, cib_sync_call);
1432 rc = pcmk_legacy2rc(rc);
1433 if (rc != pcmk_rc_ok) {
1434 out->err(out, "Could not obtain the current CIB: %s", pcmk_rc_str(rc));
1435 goto done;
1436 }
1437
1438 if (cib_xml_orig != NULL) {
1439 updated_xml = pcmk__xml_copy(NULL, queried_xml);
1440 } else {
1441
1442 updated_xml = queried_xml;
1443 queried_xml = NULL;
1444 }
1445
1446 rc = pcmk__update_configured_schema(&updated_xml, false);
1447 if (rc != pcmk_rc_ok) {
1448 out->err(out, "Could not upgrade the current CIB XML: %s",
1449 pcmk_rc_str(rc));
1450 pcmk__xml_free(updated_xml);
1451 goto done;
1452 }
1453
1454 scheduler->input = updated_xml;
1455 scheduler->priv->now = crm_time_new(NULL);
1456
1457 done:
1458 if ((rc == pcmk_rc_ok) && (cib_xml_orig != NULL)) {
1459 *cib_xml_orig = queried_xml;
1460 } else {
1461 pcmk__xml_free(queried_xml);
1462 }
1463 return rc;
1464 }
1465
1466
1467 static int
1468 update_dataset(cib_t *cib, pcmk_scheduler_t *scheduler, xmlNode **cib_xml_orig,
1469 bool simulate)
1470 {
1471 char *pid = NULL;
1472 char *shadow_file = NULL;
1473 cib_t *shadow_cib = NULL;
1474 int rc = pcmk_rc_ok;
1475
1476 pcmk__output_t *out = scheduler->priv->out;
1477
1478 pcmk_reset_scheduler(scheduler);
1479 pcmk__set_scheduler_flags(scheduler, pcmk__sched_no_counts);
1480
1481 if(simulate) {
1482 bool prev_quiet = false;
1483
1484 rc = update_scheduler_input(out, scheduler, cib, NULL);
1485 if (rc != pcmk_rc_ok) {
1486 goto done;
1487 }
1488
1489 pid = pcmk__getpid_s();
1490 shadow_cib = cib_shadow_new(pid);
1491 shadow_file = get_shadow_file(pid);
1492
1493 if (shadow_cib == NULL) {
1494 out->err(out, "Could not create shadow cib: '%s'", pid);
1495 rc = ENXIO;
1496 goto done;
1497 }
1498
1499 rc = pcmk__xml_write_file(scheduler->input, shadow_file, false);
1500 if (rc != pcmk_rc_ok) {
1501 out->err(out, "Could not populate shadow cib: %s", pcmk_rc_str(rc));
1502 goto done;
1503 }
1504
1505 rc = shadow_cib->cmds->signon(shadow_cib, crm_system_name, cib_command);
1506 rc = pcmk_legacy2rc(rc);
1507
1508 if (rc != pcmk_rc_ok) {
1509 out->err(out, "Could not connect to shadow cib: %s",
1510 pcmk_rc_str(rc));
1511 goto done;
1512 }
1513
1514 pcmk__schedule_actions(scheduler);
1515
1516 prev_quiet = out->is_quiet(out);
1517 out->quiet = true;
1518 pcmk__simulate_transition(scheduler, shadow_cib, NULL);
1519 out->quiet = prev_quiet;
1520
1521 rc = update_dataset(shadow_cib, scheduler, cib_xml_orig, false);
1522
1523 } else {
1524 xmlNode *xml = NULL;
1525
1526 rc = update_scheduler_input(out, scheduler, cib, &xml);
1527 if (rc != pcmk_rc_ok) {
1528 goto done;
1529 }
1530
1531 pcmk__xml_free(*cib_xml_orig);
1532 *cib_xml_orig = xml;
1533 cluster_status(scheduler);
1534 }
1535
1536 done:
1537
1538 cib_delete(shadow_cib);
1539 free(pid);
1540
1541 if(shadow_file) {
1542 unlink(shadow_file);
1543 free(shadow_file);
1544 }
1545
1546 return rc;
1547 }
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557 static guint
1558 max_rsc_stop_timeout(pcmk_resource_t *rsc)
1559 {
1560 long long result_ll;
1561 guint max_delay = 0;
1562 xmlNode *config = NULL;
1563 GHashTable *meta = NULL;
1564
1565 if (rsc == NULL) {
1566 return 0;
1567 }
1568
1569
1570 if (rsc->priv->children != NULL) {
1571
1572 for (GList *iter = rsc->priv->children;
1573 iter != NULL; iter = iter->next) {
1574
1575 pcmk_resource_t *child = iter->data;
1576 guint delay = max_rsc_stop_timeout(child);
1577
1578 if (delay > max_delay) {
1579 pcmk__rsc_trace(rsc,
1580 "Maximum stop timeout for %s is now %s "
1581 "due to %s", rsc->id,
1582 pcmk__readable_interval(delay), child->id);
1583 max_delay = delay;
1584 }
1585 }
1586 return max_delay;
1587 }
1588
1589
1590 config = pcmk__find_action_config(rsc, PCMK_ACTION_STOP, 0, true);
1591
1592
1593
1594
1595
1596
1597 meta = pcmk__unpack_action_meta(rsc, NULL, PCMK_ACTION_STOP, 0, config);
1598 if ((pcmk__scan_ll(g_hash_table_lookup(meta, PCMK_META_TIMEOUT),
1599 &result_ll, -1LL) == pcmk_rc_ok) && (result_ll >= 0)) {
1600 max_delay = (guint) QB_MIN(result_ll, UINT_MAX);
1601 }
1602 g_hash_table_destroy(meta);
1603
1604 return max_delay;
1605 }
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622 static guint
1623 wait_time_estimate(pcmk_scheduler_t *scheduler, const GList *resources)
1624 {
1625 guint max_delay = 0U;
1626
1627
1628 for (const GList *item = resources; item != NULL; item = item->next) {
1629 pcmk_resource_t *rsc = pe_find_resource(scheduler->priv->resources,
1630 (const char *) item->data);
1631 guint delay = max_rsc_stop_timeout(rsc);
1632
1633 if (delay > max_delay) {
1634 pcmk__rsc_trace(rsc,
1635 "Wait time is now %s due to %s",
1636 pcmk__readable_interval(delay), rsc->id);
1637 max_delay = delay;
1638 }
1639 }
1640
1641 return pcmk__timeout_ms2s(max_delay) + 5;
1642 }
1643
1644 #define waiting_for_starts(d, r, h) ((d != NULL) || \
1645 (!resource_is_running_on((r), (h))))
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668 int
1669 cli_resource_restart(pcmk__output_t *out, pcmk_resource_t *rsc,
1670 const pcmk_node_t *node, const char *move_lifetime,
1671 guint timeout_ms, cib_t *cib, gboolean promoted_role_only,
1672 gboolean force)
1673 {
1674 int rc = pcmk_rc_ok;
1675 int lpc = 0;
1676 int before = 0;
1677 guint step_timeout_s = 0;
1678
1679
1680
1681
1682 guint sleep_interval = 2U;
1683 guint timeout = pcmk__timeout_ms2s(timeout_ms);
1684
1685 bool stop_via_ban = false;
1686 char *rsc_id = NULL;
1687 char *lookup_id = NULL;
1688 char *orig_target_role = NULL;
1689 xmlNode *cib_xml_orig = NULL;
1690
1691 GList *list_delta = NULL;
1692 GList *target_active = NULL;
1693 GList *current_active = NULL;
1694 GList *restart_target_active = NULL;
1695
1696 pcmk_scheduler_t *scheduler = NULL;
1697 pcmk_resource_t *parent = uber_parent(rsc);
1698
1699 bool running = false;
1700 const char *id = pcmk__s(rsc->priv->history_id, rsc->id);
1701 const char *host = node ? node->priv->name : NULL;
1702
1703
1704
1705
1706 if (pcmk__is_bundled(rsc)) {
1707 rsc = parent->priv->parent;
1708 }
1709
1710 running = resource_is_running_on(rsc, host);
1711
1712 if (pcmk__is_clone(parent) && !running) {
1713 if (pcmk__is_unique_clone(parent)) {
1714 lookup_id = strdup(rsc->id);
1715 } else {
1716 lookup_id = clone_strip(rsc->id);
1717 }
1718
1719 rsc = parent->priv->fns->find_rsc(parent, lookup_id, node,
1720 pcmk_rsc_match_basename
1721 |pcmk_rsc_match_current_node);
1722 free(lookup_id);
1723 running = resource_is_running_on(rsc, host);
1724 }
1725
1726 if (!running) {
1727 if (host) {
1728 out->err(out, "%s is not running on %s and so cannot be restarted", id, host);
1729 } else {
1730 out->err(out, "%s is not running anywhere and so cannot be restarted", id);
1731 }
1732 return ENXIO;
1733 }
1734
1735 if (!pcmk_is_set(rsc->flags, pcmk__rsc_managed)) {
1736 out->err(out, "Unmanaged resources cannot be restarted.");
1737 return EAGAIN;
1738 }
1739
1740 rsc_id = strdup(rsc->id);
1741
1742 if (pcmk__is_unique_clone(parent)) {
1743 lookup_id = strdup(rsc->id);
1744 } else {
1745 lookup_id = clone_strip(rsc->id);
1746 }
1747
1748 if (host) {
1749 if (pcmk__is_clone(rsc) || pe_bundle_replicas(rsc)) {
1750 stop_via_ban = true;
1751 } else if (pcmk__is_clone(parent)) {
1752 stop_via_ban = true;
1753 free(lookup_id);
1754 lookup_id = strdup(parent->id);
1755 }
1756 }
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776 scheduler = pcmk_new_scheduler();
1777 if (scheduler == NULL) {
1778 rc = errno;
1779 out->err(out, "Could not allocate scheduler data: %s", pcmk_rc_str(rc));
1780 goto done;
1781 }
1782
1783 scheduler->priv->out = out;
1784 rc = update_dataset(cib, scheduler, &cib_xml_orig, false);
1785
1786 if(rc != pcmk_rc_ok) {
1787 out->err(out, "Could not get new resource list: %s (%d)", pcmk_rc_str(rc), rc);
1788 goto done;
1789 }
1790
1791 restart_target_active = get_active_resources(host,
1792 scheduler->priv->resources);
1793 current_active = get_active_resources(host, scheduler->priv->resources);
1794
1795 dump_list(current_active, "Origin");
1796
1797 if (stop_via_ban) {
1798
1799 out->quiet = true;
1800 rc = cli_resource_ban(out, lookup_id, host, move_lifetime, cib,
1801 promoted_role_only, PCMK_ROLE_PROMOTED);
1802 } else {
1803 xmlNode *xml_search = NULL;
1804
1805
1806
1807
1808
1809
1810 rc = find_resource_attr(out, cib, PCMK_XA_VALUE, lookup_id, NULL, NULL, NULL,
1811 PCMK_META_TARGET_ROLE, &xml_search);
1812
1813 if (rc == pcmk_rc_ok) {
1814 orig_target_role = crm_element_value_copy(xml_search, PCMK_XA_VALUE);
1815 }
1816
1817 pcmk__xml_free(xml_search);
1818
1819 rc = cli_resource_update_attribute(rsc, rsc_id, NULL,
1820 PCMK_XE_META_ATTRIBUTES, NULL,
1821 PCMK_META_TARGET_ROLE,
1822 PCMK_ACTION_STOPPED, FALSE, cib,
1823 cib_xml_orig, force);
1824 }
1825 if(rc != pcmk_rc_ok) {
1826 out->err(out, "Could not set " PCMK_META_TARGET_ROLE " for %s: %s (%d)",
1827 rsc_id, pcmk_rc_str(rc), rc);
1828 if (current_active != NULL) {
1829 g_list_free_full(current_active, free);
1830 current_active = NULL;
1831 }
1832 if (restart_target_active != NULL) {
1833 g_list_free_full(restart_target_active, free);
1834 restart_target_active = NULL;
1835 }
1836 goto done;
1837 }
1838
1839 rc = update_dataset(cib, scheduler, &cib_xml_orig, true);
1840 if(rc != pcmk_rc_ok) {
1841 out->err(out, "Could not determine which resources would be stopped");
1842 goto failure;
1843 }
1844
1845 target_active = get_active_resources(host, scheduler->priv->resources);
1846 dump_list(target_active, "Target");
1847
1848 list_delta = pcmk__subtract_lists(current_active, target_active, (GCompareFunc) strcmp);
1849 out->info(out, "Waiting for %d resources to stop:", g_list_length(list_delta));
1850 display_list(out, list_delta, " * ");
1851
1852 step_timeout_s = timeout / sleep_interval;
1853 while (list_delta != NULL) {
1854 before = g_list_length(list_delta);
1855 if(timeout_ms == 0) {
1856 step_timeout_s = wait_time_estimate(scheduler, list_delta)
1857 / sleep_interval;
1858 }
1859
1860
1861 for(lpc = 0; (lpc < step_timeout_s) && (list_delta != NULL); lpc++) {
1862 sleep(sleep_interval);
1863 if(timeout) {
1864 timeout -= sleep_interval;
1865 crm_trace("%us remaining", timeout);
1866 }
1867 rc = update_dataset(cib, scheduler, &cib_xml_orig, false);
1868 if(rc != pcmk_rc_ok) {
1869 out->err(out, "Could not determine which resources were stopped");
1870 goto failure;
1871 }
1872
1873 if (current_active != NULL) {
1874 g_list_free_full(current_active, free);
1875 }
1876 current_active = get_active_resources(host,
1877 scheduler->priv->resources);
1878
1879 g_list_free(list_delta);
1880 list_delta = pcmk__subtract_lists(current_active, target_active, (GCompareFunc) strcmp);
1881
1882 dump_list(current_active, "Current");
1883 dump_list(list_delta, "Delta");
1884 }
1885
1886 crm_trace("%d (was %d) resources remaining", g_list_length(list_delta), before);
1887 if(before == g_list_length(list_delta)) {
1888
1889 out->err(out, "Could not complete shutdown of %s, %d resources remaining", rsc_id, g_list_length(list_delta));
1890 display_list(out, list_delta, " * ");
1891 rc = ETIME;
1892 goto failure;
1893 }
1894
1895 }
1896
1897 if (stop_via_ban) {
1898 rc = cli_resource_clear(lookup_id, host, NULL, cib, true, force);
1899
1900 } else if (orig_target_role) {
1901 rc = cli_resource_update_attribute(rsc, rsc_id, NULL,
1902 PCMK_XE_META_ATTRIBUTES, NULL,
1903 PCMK_META_TARGET_ROLE,
1904 orig_target_role, FALSE, cib,
1905 cib_xml_orig, force);
1906 free(orig_target_role);
1907 orig_target_role = NULL;
1908 } else {
1909 rc = cli_resource_delete_attribute(rsc, rsc_id, NULL,
1910 PCMK_XE_META_ATTRIBUTES, NULL,
1911 PCMK_META_TARGET_ROLE, cib,
1912 cib_xml_orig, force);
1913 }
1914
1915 if(rc != pcmk_rc_ok) {
1916 out->err(out,
1917 "Could not unset " PCMK_META_TARGET_ROLE " for %s: %s (%d)",
1918 rsc_id, pcmk_rc_str(rc), rc);
1919 goto done;
1920 }
1921
1922 if (target_active != NULL) {
1923 g_list_free_full(target_active, free);
1924 }
1925 target_active = restart_target_active;
1926
1927 list_delta = pcmk__subtract_lists(target_active, current_active, (GCompareFunc) strcmp);
1928 out->info(out, "Waiting for %d resources to start again:", g_list_length(list_delta));
1929 display_list(out, list_delta, " * ");
1930
1931 step_timeout_s = timeout / sleep_interval;
1932 while (waiting_for_starts(list_delta, rsc, host)) {
1933 before = g_list_length(list_delta);
1934 if(timeout_ms == 0) {
1935 step_timeout_s = wait_time_estimate(scheduler, list_delta)
1936 / sleep_interval;
1937 }
1938
1939
1940 for (lpc = 0; (lpc < step_timeout_s) && waiting_for_starts(list_delta, rsc, host); lpc++) {
1941
1942 sleep(sleep_interval);
1943 if(timeout) {
1944 timeout -= sleep_interval;
1945 crm_trace("%ds remaining", timeout);
1946 }
1947
1948 rc = update_dataset(cib, scheduler, &cib_xml_orig, false);
1949 if(rc != pcmk_rc_ok) {
1950 out->err(out, "Could not determine which resources were started");
1951 goto failure;
1952 }
1953
1954
1955
1956
1957 if (current_active != NULL) {
1958 g_list_free_full(current_active, free);
1959 }
1960 current_active = get_active_resources(NULL,
1961 scheduler->priv->resources);
1962
1963 g_list_free(list_delta);
1964 list_delta = pcmk__subtract_lists(target_active, current_active, (GCompareFunc) strcmp);
1965 dump_list(current_active, "Current");
1966 dump_list(list_delta, "Delta");
1967 }
1968
1969 if(before == g_list_length(list_delta)) {
1970
1971 out->err(out, "Could not complete restart of %s, %d resources remaining", rsc_id, g_list_length(list_delta));
1972 display_list(out, list_delta, " * ");
1973 rc = ETIME;
1974 goto failure;
1975 }
1976
1977 }
1978
1979 rc = pcmk_rc_ok;
1980 goto done;
1981
1982 failure:
1983 if (stop_via_ban) {
1984 cli_resource_clear(lookup_id, host, NULL, cib, true, force);
1985 } else if (orig_target_role) {
1986 cli_resource_update_attribute(rsc, rsc_id, NULL,
1987 PCMK_XE_META_ATTRIBUTES, NULL,
1988 PCMK_META_TARGET_ROLE, orig_target_role,
1989 FALSE, cib, cib_xml_orig, force);
1990 free(orig_target_role);
1991 } else {
1992 cli_resource_delete_attribute(rsc, rsc_id, NULL,
1993 PCMK_XE_META_ATTRIBUTES, NULL,
1994 PCMK_META_TARGET_ROLE, cib, cib_xml_orig,
1995 force);
1996 }
1997
1998 done:
1999 if (list_delta != NULL) {
2000 g_list_free(list_delta);
2001 }
2002 if (current_active != NULL) {
2003 g_list_free_full(current_active, free);
2004 }
2005 if (target_active != NULL && (target_active != restart_target_active)) {
2006 g_list_free_full(target_active, free);
2007 }
2008 if (restart_target_active != NULL) {
2009 g_list_free_full(restart_target_active, free);
2010 }
2011 free(rsc_id);
2012 free(lookup_id);
2013 pcmk_free_scheduler(scheduler);
2014 return rc;
2015 }
2016
2017 static inline bool
2018 action_is_pending(const pcmk_action_t *action)
2019 {
2020 if (pcmk_any_flags_set(action->flags,
2021 pcmk__action_optional|pcmk__action_pseudo)
2022 || !pcmk_is_set(action->flags, pcmk__action_runnable)
2023 || pcmk__str_eq(PCMK_ACTION_NOTIFY, action->task, pcmk__str_casei)) {
2024 return false;
2025 }
2026 return true;
2027 }
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037 static bool
2038 actions_are_pending(const GList *actions)
2039 {
2040 for (const GList *action = actions; action != NULL; action = action->next) {
2041 const pcmk_action_t *a = (const pcmk_action_t *) action->data;
2042
2043 if (action_is_pending(a)) {
2044 crm_notice("Waiting for %s (flags=%#.8x)", a->uuid, a->flags);
2045 return true;
2046 }
2047 }
2048 return false;
2049 }
2050
2051 static void
2052 print_pending_actions(pcmk__output_t *out, GList *actions)
2053 {
2054 GList *action;
2055
2056 out->info(out, "Pending actions:");
2057 for (action = actions; action != NULL; action = action->next) {
2058 pcmk_action_t *a = (pcmk_action_t *) action->data;
2059
2060 if (!action_is_pending(a)) {
2061 continue;
2062 }
2063
2064 if (a->node) {
2065 out->info(out, "\tAction %d: %s\ton %s",
2066 a->id, a->uuid, pcmk__node_name(a->node));
2067 } else {
2068 out->info(out, "\tAction %d: %s", a->id, a->uuid);
2069 }
2070 }
2071 }
2072
2073
2074 #define WAIT_DEFAULT_TIMEOUT_S (60 * 60)
2075
2076
2077 #define WAIT_SLEEP_S (2)
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095 int
2096 wait_till_stable(pcmk__output_t *out, guint timeout_ms, cib_t * cib)
2097 {
2098
2099 pcmk_scheduler_t *scheduler = NULL;
2100 xmlXPathObject *search = NULL;
2101 int rc = pcmk_rc_ok;
2102 bool pending_unknown_state_resources;
2103 time_t expire_time = time(NULL);
2104 time_t time_diff;
2105 bool printed_version_warning = out->is_quiet(out);
2106 char *xpath = NULL;
2107
2108 if (timeout_ms == 0) {
2109 expire_time += WAIT_DEFAULT_TIMEOUT_S;
2110 } else {
2111 expire_time += pcmk__timeout_ms2s(timeout_ms + 999);
2112 }
2113
2114 scheduler = pcmk_new_scheduler();
2115 if (scheduler == NULL) {
2116 return ENOMEM;
2117 }
2118
2119 xpath = crm_strdup_printf("/" PCMK_XE_CIB "/" PCMK_XE_STATUS
2120 "/" PCMK__XE_NODE_STATE "/" PCMK__XE_LRM
2121 "/" PCMK__XE_LRM_RESOURCES
2122 "/" PCMK__XE_LRM_RESOURCE
2123 "/" PCMK__XE_LRM_RSC_OP
2124 "[@" PCMK__XA_RC_CODE "='%d']",
2125 PCMK_OCF_UNKNOWN);
2126 do {
2127
2128 time_diff = expire_time - time(NULL);
2129 if (time_diff <= 0) {
2130 print_pending_actions(out, scheduler->priv->actions);
2131 rc = ETIME;
2132 break;
2133 }
2134
2135 crm_info("Waiting up to %lld seconds for cluster actions to complete",
2136 (long long) time_diff);
2137
2138 if (rc == pcmk_rc_ok) {
2139 sleep(WAIT_SLEEP_S);
2140 }
2141
2142
2143 pcmk_reset_scheduler(scheduler);
2144 rc = update_scheduler_input(out, scheduler, cib, NULL);
2145 if (rc != pcmk_rc_ok) {
2146 break;
2147 }
2148 pcmk__set_scheduler_flags(scheduler, pcmk__sched_no_counts);
2149 pcmk__schedule_actions(scheduler);
2150
2151 if (!printed_version_warning) {
2152
2153
2154
2155
2156
2157
2158
2159
2160 const char *dc_version = NULL;
2161
2162 dc_version = g_hash_table_lookup(scheduler->priv->options,
2163 PCMK_OPT_DC_VERSION);
2164 if (!pcmk__str_eq(dc_version, PACEMAKER_VERSION "-" BUILD_VERSION, pcmk__str_casei)) {
2165 out->info(out, "warning: wait option may not work properly in "
2166 "mixed-version cluster");
2167 printed_version_warning = true;
2168 }
2169 }
2170
2171 search = pcmk__xpath_search(scheduler->input->doc, xpath);
2172 pending_unknown_state_resources = (pcmk__xpath_num_results(search) > 0);
2173 xmlXPathFreeObject(search);
2174 } while (actions_are_pending(scheduler->priv->actions)
2175 || pending_unknown_state_resources);
2176
2177 pcmk_free_scheduler(scheduler);
2178 free(xpath);
2179 return rc;
2180 }
2181
2182 static const char *
2183 get_action(const char *rsc_action) {
2184 const char *action = NULL;
2185
2186 if (pcmk__str_eq(rsc_action, "validate", pcmk__str_casei)) {
2187 action = PCMK_ACTION_VALIDATE_ALL;
2188
2189 } else if (pcmk__str_eq(rsc_action, "force-check", pcmk__str_casei)) {
2190 action = PCMK_ACTION_MONITOR;
2191
2192 } else if (pcmk__strcase_any_of(rsc_action, "force-start", "force-stop",
2193 "force-demote", "force-promote", NULL)) {
2194 action = rsc_action+6;
2195 } else {
2196 action = rsc_action;
2197 }
2198
2199 return action;
2200 }
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215 static void
2216 set_agent_environment(GHashTable *params, guint timeout_ms, int check_level,
2217 int verbosity)
2218 {
2219 g_hash_table_insert(params, crm_meta_name(PCMK_META_TIMEOUT),
2220 crm_strdup_printf("%u", timeout_ms));
2221
2222 pcmk__insert_dup(params, PCMK_XA_CRM_FEATURE_SET, CRM_FEATURE_SET);
2223
2224 if (check_level >= 0) {
2225 char *level = crm_strdup_printf("%d", check_level);
2226
2227 setenv("OCF_CHECK_LEVEL", level, 1);
2228 free(level);
2229 }
2230
2231 pcmk__set_env_option(PCMK__ENV_DEBUG, ((verbosity > 0)? "1" : "0"), true);
2232 if (verbosity > 1) {
2233 setenv("OCF_TRACE_RA", "1", 1);
2234 }
2235
2236
2237
2238
2239
2240 setenv("OCF_TRACE_FILE", "/dev/stderr", 0);
2241 }
2242
2243
2244
2245
2246
2247
2248
2249
2250 static void
2251 apply_overrides(GHashTable *params, GHashTable *overrides)
2252 {
2253 if (overrides != NULL) {
2254 GHashTableIter iter;
2255 char *name = NULL;
2256 char *value = NULL;
2257
2258 g_hash_table_iter_init(&iter, overrides);
2259 while (g_hash_table_iter_next(&iter, (gpointer *) &name,
2260 (gpointer *) &value)) {
2261 pcmk__insert_dup(params, name, value);
2262 }
2263 }
2264 }
2265
2266
2267
2268
2269 crm_exit_t
2270 cli_resource_execute_from_params(pcmk__output_t *out, const char *rsc_name,
2271 const char *rsc_class, const char *rsc_prov,
2272 const char *rsc_type, const char *rsc_action,
2273 GHashTable *params, GHashTable *override_hash,
2274 guint timeout_ms, int resource_verbose,
2275 gboolean force, int check_level)
2276 {
2277 const char *class = rsc_class;
2278 const char *action = get_action(rsc_action);
2279 crm_exit_t exit_code = CRM_EX_OK;
2280 svc_action_t *op = NULL;
2281
2282
2283 if (timeout_ms == 0U) {
2284 timeout_ms = PCMK_DEFAULT_ACTION_TIMEOUT_MS;
2285 }
2286
2287 set_agent_environment(params, timeout_ms, check_level, resource_verbose);
2288 apply_overrides(params, override_hash);
2289
2290
2291 op = services__create_resource_action(rsc_name? rsc_name : "test",
2292 rsc_class, rsc_prov, rsc_type, action,
2293 0, QB_MIN(timeout_ms, INT_MAX),
2294 params, 0);
2295 if (op == NULL) {
2296 out->err(out, "Could not execute %s using %s%s%s:%s: %s",
2297 action, rsc_class, (rsc_prov? ":" : ""),
2298 (rsc_prov? rsc_prov : ""), rsc_type, strerror(ENOMEM));
2299 g_hash_table_destroy(params);
2300 return CRM_EX_OSERR;
2301 }
2302
2303 #if PCMK__ENABLE_SERVICE
2304 if (pcmk__str_eq(rsc_class, PCMK_RESOURCE_CLASS_SERVICE, pcmk__str_casei)) {
2305 class = resources_find_service_class(rsc_type);
2306 }
2307 #endif
2308
2309 if (!pcmk_is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_cli_exec)) {
2310 services__format_result(op, CRM_EX_UNIMPLEMENT_FEATURE, PCMK_EXEC_ERROR,
2311 "Manual execution of the %s standard is "
2312 "unsupported", pcmk__s(class, "unspecified"));
2313 }
2314
2315 if (op->rc != PCMK_OCF_UNKNOWN) {
2316 exit_code = op->rc;
2317 goto done;
2318 }
2319
2320 services_action_sync(op);
2321
2322
2323 {
2324 enum ocf_exitcode ocf_code = services_result2ocf(class, action, op->rc);
2325
2326
2327 exit_code = (crm_exit_t) ocf_code;
2328 }
2329
2330 done:
2331 out->message(out, "resource-agent-action", resource_verbose, rsc_class,
2332 rsc_prov, rsc_type, rsc_name, rsc_action, override_hash,
2333 exit_code, op->status, services__exit_reason(op),
2334 op->stdout_data, op->stderr_data);
2335 services_action_free(op);
2336 return exit_code;
2337 }
2338
2339
2340
2341
2342
2343
2344
2345
2346 static guint
2347 get_action_timeout(pcmk_resource_t *rsc, const char *action)
2348 {
2349 long long timeout_ms = -1LL;
2350 xmlNode *op = pcmk__find_action_config(rsc, action, 0, true);
2351 GHashTable *meta = pcmk__unpack_action_meta(rsc, NULL, action, 0, op);
2352
2353 if ((pcmk__scan_ll(g_hash_table_lookup(meta, PCMK_META_TIMEOUT),
2354 &timeout_ms, -1LL) != pcmk_rc_ok)
2355 || (timeout_ms <= 0LL)) {
2356 timeout_ms = PCMK_DEFAULT_ACTION_TIMEOUT_MS;
2357 }
2358 g_hash_table_destroy(meta);
2359 return (guint) QB_MIN(timeout_ms, UINT_MAX);
2360 }
2361
2362
2363 crm_exit_t
2364 cli_resource_execute(pcmk_resource_t *rsc, const char *requested_name,
2365 const char *rsc_action, GHashTable *override_hash,
2366 guint timeout_ms, cib_t *cib, int resource_verbose,
2367 bool force, int check_level)
2368 {
2369 pcmk_scheduler_t *scheduler = NULL;
2370 pcmk__output_t *out = NULL;
2371 crm_exit_t exit_code = CRM_EX_OK;
2372 const char *rid = requested_name;
2373 const char *rtype = NULL;
2374 const char *rprov = NULL;
2375 const char *rclass = NULL;
2376 GHashTable *params = NULL;
2377
2378 pcmk__assert(rsc != NULL);
2379
2380 scheduler = rsc->priv->scheduler;
2381 out = scheduler->priv->out;
2382
2383 if (pcmk__strcase_any_of(rsc_action, "force-start", "force-demote",
2384 "force-promote", NULL)) {
2385 if (pcmk__is_clone(rsc)) {
2386 GList *nodes = cli_resource_search(rsc, requested_name);
2387
2388 if(nodes != NULL && force == FALSE) {
2389 out->err(out, "It is not safe to %s %s here: the cluster claims it is already active",
2390 rsc_action, rsc->id);
2391 out->err(out,
2392 "Try setting "
2393 PCMK_META_TARGET_ROLE "=" PCMK_ROLE_STOPPED
2394 " first or specifying the force option");
2395 return CRM_EX_UNSAFE;
2396 }
2397
2398 g_list_free_full(nodes, free);
2399 }
2400 }
2401
2402 if (pcmk__is_clone(rsc)) {
2403
2404 rsc = rsc->priv->children->data;
2405 }
2406
2407 if (pcmk__is_group(rsc)) {
2408 out->err(out, "Sorry, the %s option doesn't support group resources", rsc_action);
2409 return CRM_EX_UNIMPLEMENT_FEATURE;
2410 } else if (pcmk__is_bundled(rsc)) {
2411 out->err(out, "Sorry, the %s option doesn't support bundled resources", rsc_action);
2412 return CRM_EX_UNIMPLEMENT_FEATURE;
2413 }
2414
2415 rclass = crm_element_value(rsc->priv->xml, PCMK_XA_CLASS);
2416 rprov = crm_element_value(rsc->priv->xml, PCMK_XA_PROVIDER);
2417 rtype = crm_element_value(rsc->priv->xml, PCMK_XA_TYPE);
2418
2419 params = generate_resource_params(rsc);
2420
2421 if (timeout_ms == 0U) {
2422 timeout_ms = get_action_timeout(rsc, get_action(rsc_action));
2423 }
2424
2425 if (!pcmk__is_anonymous_clone(rsc->priv->parent)) {
2426 rid = rsc->id;
2427 }
2428
2429 exit_code = cli_resource_execute_from_params(out, rid, rclass, rprov, rtype, rsc_action,
2430 params, override_hash, timeout_ms,
2431 resource_verbose, force, check_level);
2432 return exit_code;
2433 }
2434
2435
2436 int
2437 cli_resource_move(pcmk_resource_t *rsc, const char *rsc_id,
2438 const pcmk_node_t *dest, const char *move_lifetime,
2439 cib_t *cib, bool promoted_role_only, bool force)
2440 {
2441 pcmk_scheduler_t *scheduler = NULL;
2442 pcmk__output_t *out = NULL;
2443 int rc = pcmk_rc_ok;
2444 unsigned int count = 0;
2445 pcmk_node_t *current = NULL;
2446 bool cur_is_dest = false;
2447 const char *active_s = promoted_role_only? "promoted" : "active";
2448
2449 pcmk__assert((rsc != NULL) && (dest != NULL));
2450
2451 scheduler = rsc->priv->scheduler;
2452 out = scheduler->priv->out;
2453
2454 if (promoted_role_only
2455 && !pcmk_is_set(rsc->flags, pcmk__rsc_promotable)) {
2456
2457 pcmk_resource_t *p = uber_parent(rsc);
2458
2459 if (pcmk_is_set(p->flags, pcmk__rsc_promotable)) {
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477 out->info(out, "Using parent '%s' for move instead of '%s'",
2478 rsc->id, rsc_id);
2479 rsc_id = p->id;
2480 rsc = p;
2481
2482 } else {
2483 out->info(out, "Ignoring --promoted option: %s is not promotable",
2484 rsc_id);
2485 promoted_role_only = false;
2486 }
2487 }
2488
2489 current = pe__find_active_requires(rsc, &count);
2490
2491 if (pcmk_is_set(rsc->flags, pcmk__rsc_promotable)) {
2492 unsigned int promoted_count = 0;
2493 pcmk_node_t *promoted_node = NULL;
2494
2495 for (GList *iter = rsc->priv->children; iter != NULL;
2496 iter = iter->next) {
2497
2498 pcmk_resource_t *child = iter->data;
2499 enum rsc_role_e child_role = child->priv->fns->state(child, true);
2500
2501 if (child_role == pcmk_role_promoted) {
2502 rsc = child;
2503 promoted_node = pcmk__current_node(child);
2504 promoted_count++;
2505 }
2506 }
2507 if (promoted_role_only || (promoted_count != 0)) {
2508 count = promoted_count;
2509 current = promoted_node;
2510 }
2511 }
2512
2513 if (count > 1) {
2514 if (!pcmk__is_clone(rsc)) {
2515 return pcmk_rc_multiple;
2516 }
2517 current = NULL;
2518 }
2519
2520 if (pcmk__same_node(current, dest)) {
2521 if (!force) {
2522 return pcmk_rc_already;
2523 }
2524
2525 cur_is_dest = true;
2526 crm_info("%s is already %s on %s, reinforcing placement with location "
2527 "constraint",
2528 rsc_id, active_s, pcmk__node_name(dest));
2529 }
2530
2531
2532
2533
2534
2535
2536
2537 cli_resource_clear(rsc_id, NULL, scheduler->nodes, cib, false, force);
2538
2539
2540 cli_resource_clear(rsc_id, dest->priv->name, scheduler->nodes, cib, true,
2541 force);
2542
2543
2544 rc = cli_resource_prefer(out, rsc_id, dest->priv->name, move_lifetime,
2545 cib, promoted_role_only, PCMK_ROLE_PROMOTED);
2546
2547 crm_trace("%s%s now prefers %s%s",
2548 rsc->id, (promoted_role_only? " (promoted)" : ""),
2549 pcmk__node_name(dest), (force? " (forced)" : ""));
2550
2551
2552
2553
2554
2555 if (force && !cur_is_dest) {
2556
2557 if (current != NULL) {
2558 cli_resource_ban(out, rsc_id, current->priv->name, move_lifetime,
2559 cib, promoted_role_only, PCMK_ROLE_PROMOTED);
2560
2561 } else if (count > 1) {
2562 out->info(out,
2563 "Resource '%s' is currently %s in %u locations. "
2564 "One may now move to %s",
2565 rsc_id, active_s, count, pcmk__node_name(dest));
2566 out->info(out,
2567 "To prevent '%s' from being %s at a specific location, "
2568 "specify a node",
2569 rsc_id, active_s);
2570
2571 } else {
2572 crm_trace("Not banning %s from its current location: not active",
2573 rsc_id);
2574 }
2575 }
2576
2577 return rc;
2578 }