This source file includes following definitions.
- build_node_info_list
- cli_resource_search
- find_resource_attr
- find_matching_attr_resources_recursive
- find_matching_attr_resources
- 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_working_set_xml
- update_working_set_from_cib
- update_dataset
- max_delay_for_resource
- max_delay_in
- 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
- cli_resource_execute
- cli_resource_move
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <crm_resource.h>
13 #include <crm/common/ipc_attrd_internal.h>
14 #include <crm/common/ipc_controld.h>
15 #include <crm/common/lists_internal.h>
16 #include <crm/services_internal.h>
17
18 static GList *
19 build_node_info_list(pe_resource_t *rsc)
20 {
21 GList *retval = NULL;
22
23 for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
24 pe_resource_t *child = (pe_resource_t *) iter->data;
25
26 for (GList *iter2 = child->running_on; iter2 != NULL; iter2 = iter2->next) {
27 pe_node_t *node = (pe_node_t *) iter2->data;
28 node_info_t *ni = calloc(1, sizeof(node_info_t));
29 ni->node_name = node->details->uname;
30 ni->promoted = pcmk_is_set(rsc->flags, pe_rsc_promotable) &&
31 child->fns->state(child, TRUE) == RSC_ROLE_PROMOTED;
32
33 retval = g_list_prepend(retval, ni);
34 }
35 }
36
37 return retval;
38 }
39
40 GList *
41 cli_resource_search(pe_resource_t *rsc, const char *requested_name,
42 pe_working_set_t *data_set)
43 {
44 GList *retval = NULL;
45 pe_resource_t *parent = uber_parent(rsc);
46
47 if (pe_rsc_is_clone(rsc)) {
48 retval = build_node_info_list(rsc);
49
50
51 } else if (pe_rsc_is_clone(parent)
52 && !pcmk_is_set(rsc->flags, pe_rsc_unique)
53 && rsc->clone_name
54 && pcmk__str_eq(requested_name, rsc->clone_name, pcmk__str_casei)
55 && !pcmk__str_eq(requested_name, rsc->id, pcmk__str_casei)) {
56
57 retval = build_node_info_list(parent);
58
59 } else if (rsc->running_on != NULL) {
60 for (GList *iter = rsc->running_on; iter != NULL; iter = iter->next) {
61 pe_node_t *node = (pe_node_t *) iter->data;
62 node_info_t *ni = calloc(1, sizeof(node_info_t));
63 ni->node_name = node->details->uname;
64 ni->promoted = (rsc->fns->state(rsc, TRUE) == RSC_ROLE_PROMOTED);
65
66 retval = g_list_prepend(retval, ni);
67 }
68 }
69
70 return retval;
71 }
72
73
74 static int
75 find_resource_attr(pcmk__output_t *out, cib_t * the_cib, const char *attr,
76 const char *rsc, const char *attr_set_type, const char *set_name,
77 const char *attr_id, const char *attr_name, char **value)
78 {
79 int rc = pcmk_rc_ok;
80 xmlNode *xml_search = NULL;
81 GString *xpath = NULL;
82 const char *xpath_base = NULL;
83
84 if(value) {
85 *value = NULL;
86 }
87
88 if(the_cib == NULL) {
89 return ENOTCONN;
90 }
91
92 xpath_base = pcmk_cib_xpath_for(XML_CIB_TAG_RESOURCES);
93 if (xpath_base == NULL) {
94 crm_err(XML_CIB_TAG_RESOURCES " CIB element not known (bug?)");
95 return ENOMSG;
96 }
97
98 xpath = g_string_sized_new(1024);
99 pcmk__g_strcat(xpath,
100 xpath_base, "//*[@" XML_ATTR_ID "=\"", rsc, "\"]", NULL);
101
102 if (attr_set_type != NULL) {
103 pcmk__g_strcat(xpath, "/", attr_set_type, NULL);
104 if (set_name != NULL) {
105 pcmk__g_strcat(xpath, "[@" XML_ATTR_ID "=\"", set_name, "\"]",
106 NULL);
107 }
108 }
109
110 g_string_append(xpath, "//" XML_CIB_TAG_NVPAIR "[");
111 if (attr_id != NULL) {
112 pcmk__g_strcat(xpath, "@" XML_ATTR_ID "=\"", attr_id, "\"", NULL);
113 }
114
115 if (attr_name != NULL) {
116 if (attr_id != NULL) {
117 g_string_append(xpath, " and ");
118 }
119 pcmk__g_strcat(xpath, "@" XML_NVPAIR_ATTR_NAME "=\"", attr_name, "\"",
120 NULL);
121 }
122 g_string_append_c(xpath, ']');
123
124 rc = the_cib->cmds->query(the_cib, (const char *) xpath->str, &xml_search,
125 cib_sync_call | cib_scope_local | cib_xpath);
126 rc = pcmk_legacy2rc(rc);
127
128 if (rc != pcmk_rc_ok) {
129 goto done;
130 }
131
132 crm_log_xml_debug(xml_search, "Match");
133 if (xml_has_children(xml_search)) {
134 xmlNode *child = NULL;
135
136 rc = ENOTUNIQ;
137 out->info(out, "Multiple attributes match name=%s", attr_name);
138
139 for (child = pcmk__xml_first_child(xml_search); child != NULL;
140 child = pcmk__xml_next(child)) {
141 out->info(out, " Value: %s \t(id=%s)",
142 crm_element_value(child, XML_NVPAIR_ATTR_VALUE), ID(child));
143 }
144
145 out->spacer(out);
146
147 } else if(value) {
148 pcmk__str_update(value, crm_element_value(xml_search, attr));
149 }
150
151 done:
152 g_string_free(xpath, TRUE);
153 free_xml(xml_search);
154 return rc;
155 }
156
157
158 static void
159 find_matching_attr_resources_recursive(pcmk__output_t *out, GList ** result,
160 pe_resource_t * rsc, const char * rsc_id,
161 const char * attr_set, const char * attr_set_type,
162 const char * attr_id, const char * attr_name,
163 cib_t * cib, const char * cmd, int depth)
164 {
165 int rc = pcmk_rc_ok;
166 char *lookup_id = clone_strip(rsc->id);
167 char *local_attr_id = NULL;
168
169
170 for(GList *gIter = rsc->children; gIter; gIter = gIter->next) {
171 find_matching_attr_resources_recursive(out, result, (pe_resource_t*)gIter->data,
172 rsc_id, attr_set, attr_set_type,
173 attr_id, attr_name, cib, cmd, depth+1);
174
175 if(pe_clone == rsc->variant) {
176 break;
177 }
178 }
179
180 rc = find_resource_attr(out, cib, XML_ATTR_ID, lookup_id, attr_set_type,
181 attr_set, attr_id, attr_name, &local_attr_id);
182
183
184 if((0 == depth) || (pcmk_rc_ok == rc)) {
185
186 *result = g_list_append(*result, rsc);
187 }
188
189 free(local_attr_id);
190 free(lookup_id);
191 }
192
193
194
195 static GList *
196 find_matching_attr_resources(pcmk__output_t *out, pe_resource_t * rsc,
197 const char * rsc_id, const char * attr_set,
198 const char * attr_set_type, const char * attr_id,
199 const char * attr_name, cib_t * cib, const char * cmd,
200 gboolean force)
201 {
202 int rc = pcmk_rc_ok;
203 char *lookup_id = NULL;
204 char *local_attr_id = NULL;
205 GList * result = NULL;
206
207
208
209 if(force == TRUE) {
210 return g_list_append(result, rsc);
211 }
212 if(rsc->parent && pe_clone == rsc->parent->variant) {
213 int rc = pcmk_rc_ok;
214 char *local_attr_id = NULL;
215 rc = find_resource_attr(out, cib, XML_ATTR_ID, rsc_id, attr_set_type,
216 attr_set, attr_id, attr_name, &local_attr_id);
217 free(local_attr_id);
218
219 if(rc != pcmk_rc_ok) {
220 rsc = rsc->parent;
221 out->info(out, "Performing %s of '%s' on '%s', the parent of '%s'",
222 cmd, attr_name, rsc->id, rsc_id);
223 }
224 return g_list_append(result, rsc);
225 } else if(rsc->parent == NULL && rsc->children && pe_clone == rsc->variant) {
226 pe_resource_t *child = rsc->children->data;
227
228 if(child->variant == pe_native) {
229 lookup_id = clone_strip(child->id);
230 rc = find_resource_attr(out, cib, XML_ATTR_ID, lookup_id, attr_set_type,
231 attr_set, attr_id, attr_name, &local_attr_id);
232
233 if(rc == pcmk_rc_ok) {
234 rsc = child;
235 out->info(out, "A value for '%s' already exists in child '%s', performing %s on that instead of '%s'",
236 attr_name, lookup_id, cmd, rsc_id);
237 }
238
239 free(local_attr_id);
240 free(lookup_id);
241 }
242 return g_list_append(result, rsc);
243 }
244
245 find_matching_attr_resources_recursive(out, &result, rsc, rsc_id, attr_set,
246 attr_set_type, attr_id, attr_name,
247 cib, cmd, 0);
248 return result;
249 }
250
251
252 int
253 cli_resource_update_attribute(pe_resource_t *rsc, const char *requested_name,
254 const char *attr_set, const char *attr_set_type,
255 const char *attr_id, const char *attr_name,
256 const char *attr_value, gboolean recursive,
257 cib_t *cib, int cib_options,
258 pe_working_set_t *data_set, gboolean force)
259 {
260 pcmk__output_t *out = data_set->priv;
261 int rc = pcmk_rc_ok;
262 static bool need_init = true;
263
264 char *local_attr_id = NULL;
265 char *local_attr_set = NULL;
266
267 GList *resources = NULL;
268 const char *common_attr_id = attr_id;
269
270 if (attr_id == NULL && force == FALSE) {
271 find_resource_attr (out, cib, XML_ATTR_ID, uber_parent(rsc)->id, NULL,
272 NULL, NULL, attr_name, NULL);
273 }
274
275 if (pcmk__str_eq(attr_set_type, XML_TAG_ATTR_SETS, pcmk__str_casei)) {
276 if (force == FALSE) {
277 rc = find_resource_attr(out, cib, XML_ATTR_ID, uber_parent(rsc)->id,
278 XML_TAG_META_SETS, attr_set, attr_id,
279 attr_name, &local_attr_id);
280 if (rc == pcmk_rc_ok && !out->is_quiet(out)) {
281 out->err(out, "WARNING: There is already a meta attribute for '%s' called '%s' (id=%s)",
282 uber_parent(rsc)->id, attr_name, local_attr_id);
283 out->err(out, " Delete '%s' first or use the force option to override",
284 local_attr_id);
285 }
286 free(local_attr_id);
287 if (rc == pcmk_rc_ok) {
288 return ENOTUNIQ;
289 }
290 }
291 resources = g_list_append(resources, rsc);
292
293 } else {
294 resources = find_matching_attr_resources(out, rsc, requested_name, attr_set, attr_set_type,
295 attr_id, attr_name, cib, "update", force);
296 }
297
298
299
300
301 for(GList *gIter = (attr_set||attr_id) ? g_list_last(resources) : resources
302 ; gIter; gIter = gIter->next) {
303 char *lookup_id = NULL;
304
305 xmlNode *xml_top = NULL;
306 xmlNode *xml_obj = NULL;
307 local_attr_id = NULL;
308 local_attr_set = NULL;
309
310 rsc = (pe_resource_t*)gIter->data;
311 attr_id = common_attr_id;
312
313 lookup_id = clone_strip(rsc->id);
314 rc = find_resource_attr(out, cib, XML_ATTR_ID, lookup_id, attr_set_type,
315 attr_set, attr_id, attr_name, &local_attr_id);
316
317 if (rc == pcmk_rc_ok) {
318 crm_debug("Found a match for name=%s: id=%s", attr_name, local_attr_id);
319 attr_id = local_attr_id;
320
321 } else if (rc != ENXIO) {
322 free(lookup_id);
323 free(local_attr_id);
324 g_list_free(resources);
325 return rc;
326
327 } else {
328 const char *tag = crm_element_name(rsc->xml);
329
330 if (attr_set == NULL) {
331 local_attr_set = crm_strdup_printf("%s-%s", lookup_id,
332 attr_set_type);
333 attr_set = local_attr_set;
334 }
335 if (attr_id == NULL) {
336 local_attr_id = crm_strdup_printf("%s-%s", attr_set, attr_name);
337 attr_id = local_attr_id;
338 }
339
340 xml_top = create_xml_node(NULL, tag);
341 crm_xml_add(xml_top, XML_ATTR_ID, lookup_id);
342
343 xml_obj = create_xml_node(xml_top, attr_set_type);
344 crm_xml_add(xml_obj, XML_ATTR_ID, attr_set);
345 }
346
347 xml_obj = crm_create_nvpair_xml(xml_obj, attr_id, attr_name, attr_value);
348 if (xml_top == NULL) {
349 xml_top = xml_obj;
350 }
351
352 crm_log_xml_debug(xml_top, "Update");
353
354 rc = cib->cmds->modify(cib, XML_CIB_TAG_RESOURCES, xml_top, cib_options);
355 rc = pcmk_legacy2rc(rc);
356
357 if (rc == pcmk_rc_ok) {
358 out->info(out, "Set '%s' option: id=%s%s%s%s%s value=%s", lookup_id, local_attr_id,
359 attr_set ? " set=" : "", attr_set ? attr_set : "",
360 attr_name ? " name=" : "", attr_name ? attr_name : "", attr_value);
361 }
362
363 free_xml(xml_top);
364
365 free(lookup_id);
366 free(local_attr_id);
367 free(local_attr_set);
368
369 if(recursive && pcmk__str_eq(attr_set_type, XML_TAG_META_SETS, pcmk__str_casei)) {
370 GList *lpc = NULL;
371
372 if(need_init) {
373 need_init = false;
374 pcmk__unpack_constraints(data_set);
375 pe__clear_resource_flags_on_all(data_set, pe_rsc_allocating);
376 }
377
378 crm_debug("Looking for dependencies %p", rsc->rsc_cons_lhs);
379 pe__set_resource_flags(rsc, pe_rsc_allocating);
380 for (lpc = rsc->rsc_cons_lhs; lpc != NULL; lpc = lpc->next) {
381 pcmk__colocation_t *cons = (pcmk__colocation_t *) lpc->data;
382
383 crm_debug("Checking %s %d", cons->id, cons->score);
384 if ((cons->score > 0)
385 && !pcmk_is_set(cons->dependent->flags, pe_rsc_allocating)) {
386
387 crm_debug("Setting %s=%s for dependent resource %s",
388 attr_name, attr_value, cons->dependent->id);
389 cli_resource_update_attribute(cons->dependent,
390 cons->dependent->id, NULL,
391 attr_set_type, NULL,
392 attr_name, attr_value,
393 recursive, cib, cib_options,
394 data_set, force);
395 }
396 }
397 }
398 }
399 g_list_free(resources);
400 return rc;
401 }
402
403
404 int
405 cli_resource_delete_attribute(pe_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 cib_t *cib, int cib_options,
409 pe_working_set_t *data_set, gboolean force)
410 {
411 pcmk__output_t *out = data_set->priv;
412 int rc = pcmk_rc_ok;
413 GList *resources = NULL;
414
415 if (attr_id == NULL && force == FALSE) {
416 find_resource_attr(out, cib, XML_ATTR_ID, uber_parent(rsc)->id, NULL,
417 NULL, NULL, attr_name, NULL);
418 }
419
420 if(pcmk__str_eq(attr_set_type, XML_TAG_META_SETS, pcmk__str_casei)) {
421 resources = find_matching_attr_resources(out, rsc, requested_name, attr_set, attr_set_type,
422 attr_id, attr_name, cib, "delete", force);
423 } else {
424 resources = g_list_append(resources, rsc);
425 }
426
427 for(GList *gIter = resources; gIter; gIter = gIter->next) {
428 char *lookup_id = NULL;
429 xmlNode *xml_obj = NULL;
430 char *local_attr_id = NULL;
431
432 rsc = (pe_resource_t*)gIter->data;
433
434 lookup_id = clone_strip(rsc->id);
435 rc = find_resource_attr(out, cib, XML_ATTR_ID, lookup_id, attr_set_type,
436 attr_set, attr_id, attr_name, &local_attr_id);
437
438 if (rc == ENXIO) {
439 free(lookup_id);
440 rc = pcmk_rc_ok;
441 continue;
442
443 } else if (rc != pcmk_rc_ok) {
444 free(lookup_id);
445 g_list_free(resources);
446 return rc;
447 }
448
449 if (attr_id == NULL) {
450 attr_id = local_attr_id;
451 }
452
453 xml_obj = crm_create_nvpair_xml(NULL, attr_id, attr_name, NULL);
454 crm_log_xml_debug(xml_obj, "Delete");
455
456 CRM_ASSERT(cib);
457 rc = cib->cmds->remove(cib, XML_CIB_TAG_RESOURCES, xml_obj, cib_options);
458 rc = pcmk_legacy2rc(rc);
459
460 if (rc == pcmk_rc_ok) {
461 out->info(out, "Deleted '%s' option: id=%s%s%s%s%s", lookup_id, local_attr_id,
462 attr_set ? " set=" : "", attr_set ? attr_set : "",
463 attr_name ? " name=" : "", attr_name ? attr_name : "");
464 }
465
466 free(lookup_id);
467 free_xml(xml_obj);
468 free(local_attr_id);
469 }
470 g_list_free(resources);
471 return rc;
472 }
473
474
475 static int
476 send_lrm_rsc_op(pcmk_ipc_api_t *controld_api, bool do_fail_resource,
477 const char *host_uname, const char *rsc_id, pe_working_set_t *data_set)
478 {
479 pcmk__output_t *out = data_set->priv;
480 const char *router_node = host_uname;
481 const char *rsc_api_id = NULL;
482 const char *rsc_long_id = NULL;
483 const char *rsc_class = NULL;
484 const char *rsc_provider = NULL;
485 const char *rsc_type = NULL;
486 bool cib_only = false;
487 pe_resource_t *rsc = pe_find_resource(data_set->resources, rsc_id);
488
489 if (rsc == NULL) {
490 out->err(out, "Resource %s not found", rsc_id);
491 return ENXIO;
492
493 } else if (rsc->variant != pe_native) {
494 out->err(out, "We can only process primitive resources, not %s", rsc_id);
495 return EINVAL;
496 }
497
498 rsc_class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
499 rsc_provider = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER),
500 rsc_type = crm_element_value(rsc->xml, XML_ATTR_TYPE);
501 if ((rsc_class == NULL) || (rsc_type == NULL)) {
502 out->err(out, "Resource %s does not have a class and type", rsc_id);
503 return EINVAL;
504 }
505
506 {
507 pe_node_t *node = pe_find_node(data_set->nodes, host_uname);
508
509 if (node == NULL) {
510 out->err(out, "Node %s not found", host_uname);
511 return pcmk_rc_node_unknown;
512 }
513
514 if (!(node->details->online)) {
515 if (do_fail_resource) {
516 out->err(out, "Node %s is not online", host_uname);
517 return ENOTCONN;
518 } else {
519 cib_only = true;
520 }
521 }
522 if (!cib_only && pe__is_guest_or_remote_node(node)) {
523 node = pe__current_node(node->details->remote_rsc);
524 if (node == NULL) {
525 out->err(out, "No cluster connection to Pacemaker Remote node %s detected",
526 host_uname);
527 return ENOTCONN;
528 }
529 router_node = node->details->uname;
530 }
531 }
532
533 if (rsc->clone_name) {
534 rsc_api_id = rsc->clone_name;
535 rsc_long_id = rsc->id;
536 } else {
537 rsc_api_id = rsc->id;
538 }
539 if (do_fail_resource) {
540 return pcmk_controld_api_fail(controld_api, host_uname, router_node,
541 rsc_api_id, rsc_long_id,
542 rsc_class, rsc_provider, rsc_type);
543 } else {
544 return pcmk_controld_api_refresh(controld_api, host_uname, router_node,
545 rsc_api_id, rsc_long_id, rsc_class,
546 rsc_provider, rsc_type, cib_only);
547 }
548 }
549
550
551
552
553
554
555
556
557
558
559 static inline char *
560 rsc_fail_name(pe_resource_t *rsc)
561 {
562 const char *name = (rsc->clone_name? rsc->clone_name : rsc->id);
563
564 return pcmk_is_set(rsc->flags, pe_rsc_unique)? strdup(name) : clone_strip(name);
565 }
566
567
568 static int
569 clear_rsc_history(pcmk_ipc_api_t *controld_api, const char *host_uname,
570 const char *rsc_id, pe_working_set_t *data_set)
571 {
572 int rc = pcmk_rc_ok;
573
574
575
576
577
578
579 rc = send_lrm_rsc_op(controld_api, false, host_uname, rsc_id, data_set);
580 if (rc != pcmk_rc_ok) {
581 return rc;
582 }
583
584 crm_trace("Processing %d mainloop inputs",
585 pcmk_controld_api_replies_expected(controld_api));
586 while (g_main_context_iteration(NULL, FALSE)) {
587 crm_trace("Processed mainloop input, %d still remaining",
588 pcmk_controld_api_replies_expected(controld_api));
589 }
590 return rc;
591 }
592
593
594 static int
595 clear_rsc_failures(pcmk__output_t *out, pcmk_ipc_api_t *controld_api,
596 const char *node_name, const char *rsc_id, const char *operation,
597 const char *interval_spec, pe_working_set_t *data_set)
598 {
599 int rc = pcmk_rc_ok;
600 const char *failed_value = NULL;
601 const char *failed_id = NULL;
602 const char *interval_ms_s = NULL;
603 GHashTable *rscs = NULL;
604 GHashTableIter iter;
605
606
607
608
609
610 rscs = pcmk__strkey_table(NULL, NULL);
611
612
613 if (operation) {
614 interval_ms_s = crm_strdup_printf("%u",
615 crm_parse_interval_spec(interval_spec));
616 }
617
618 for (xmlNode *xml_op = pcmk__xml_first_child(data_set->failed);
619 xml_op != NULL;
620 xml_op = pcmk__xml_next(xml_op)) {
621
622 failed_id = crm_element_value(xml_op, XML_LRM_ATTR_RSCID);
623 if (failed_id == NULL) {
624
625 continue;
626 }
627
628
629 if (rsc_id) {
630 pe_resource_t *fail_rsc = pe_find_resource_with_flags(data_set->resources,
631 failed_id,
632 pe_find_renamed|pe_find_anon);
633
634 if (!fail_rsc || !pcmk__str_eq(rsc_id, fail_rsc->id, pcmk__str_casei)) {
635 continue;
636 }
637 }
638
639
640 failed_value = crm_element_value(xml_op, XML_ATTR_UNAME);
641 if (!pcmk__str_eq(node_name, failed_value, pcmk__str_casei)) {
642 continue;
643 }
644
645
646 if (operation) {
647 failed_value = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
648 if (!pcmk__str_eq(operation, failed_value, pcmk__str_casei)) {
649 continue;
650 }
651
652
653 failed_value = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL_MS);
654 if (!pcmk__str_eq(interval_ms_s, failed_value, pcmk__str_casei)) {
655 continue;
656 }
657 }
658
659 g_hash_table_add(rscs, (gpointer) failed_id);
660 }
661
662 g_hash_table_iter_init(&iter, rscs);
663 while (g_hash_table_iter_next(&iter, (gpointer *) &failed_id, NULL)) {
664 crm_debug("Erasing failures of %s on %s", failed_id, node_name);
665 rc = clear_rsc_history(controld_api, node_name, failed_id, data_set);
666 if (rc != pcmk_rc_ok) {
667 return rc;
668 }
669 }
670 g_hash_table_destroy(rscs);
671 return rc;
672 }
673
674
675 static int
676 clear_rsc_fail_attrs(pe_resource_t *rsc, const char *operation,
677 const char *interval_spec, pe_node_t *node)
678 {
679 int rc = pcmk_rc_ok;
680 int attr_options = pcmk__node_attr_none;
681 char *rsc_name = rsc_fail_name(rsc);
682
683 if (pe__is_guest_or_remote_node(node)) {
684 attr_options |= pcmk__node_attr_remote;
685 }
686
687 rc = pcmk__attrd_api_clear_failures(NULL, node->details->uname, rsc_name,
688 operation, interval_spec, NULL,
689 attr_options);
690 free(rsc_name);
691 return rc;
692 }
693
694
695 int
696 cli_resource_delete(pcmk_ipc_api_t *controld_api, const char *host_uname,
697 pe_resource_t *rsc, const char *operation,
698 const char *interval_spec, bool just_failures,
699 pe_working_set_t *data_set, gboolean force)
700 {
701 pcmk__output_t *out = data_set->priv;
702 int rc = pcmk_rc_ok;
703 pe_node_t *node = NULL;
704
705 if (rsc == NULL) {
706 return ENXIO;
707
708 } else if (rsc->children) {
709 GList *lpc = NULL;
710
711 for (lpc = rsc->children; lpc != NULL; lpc = lpc->next) {
712 pe_resource_t *child = (pe_resource_t *) lpc->data;
713
714 rc = cli_resource_delete(controld_api, host_uname, child, operation,
715 interval_spec, just_failures, data_set, force);
716 if (rc != pcmk_rc_ok) {
717 return rc;
718 }
719 }
720 return pcmk_rc_ok;
721
722 } else if (host_uname == NULL) {
723 GList *lpc = NULL;
724 GList *nodes = g_hash_table_get_values(rsc->known_on);
725
726 if(nodes == NULL && force) {
727 nodes = pcmk__copy_node_list(data_set->nodes, false);
728
729 } else if(nodes == NULL && rsc->exclusive_discover) {
730 GHashTableIter iter;
731 pe_node_t *node = NULL;
732
733 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
734 while (g_hash_table_iter_next(&iter, NULL, (void**)&node)) {
735 if(node->weight >= 0) {
736 nodes = g_list_prepend(nodes, node);
737 }
738 }
739
740 } else if(nodes == NULL) {
741 nodes = g_hash_table_get_values(rsc->allowed_nodes);
742 }
743
744 for (lpc = nodes; lpc != NULL; lpc = lpc->next) {
745 node = (pe_node_t *) lpc->data;
746
747 if (node->details->online) {
748 rc = cli_resource_delete(controld_api, node->details->uname, rsc,
749 operation, interval_spec, just_failures,
750 data_set, force);
751 }
752 if (rc != pcmk_rc_ok) {
753 g_list_free(nodes);
754 return rc;
755 }
756 }
757
758 g_list_free(nodes);
759 return pcmk_rc_ok;
760 }
761
762 node = pe_find_node(data_set->nodes, host_uname);
763
764 if (node == NULL) {
765 out->err(out, "Unable to clean up %s because node %s not found",
766 rsc->id, host_uname);
767 return ENODEV;
768 }
769
770 if (!node->details->rsc_discovery_enabled) {
771 out->err(out, "Unable to clean up %s because resource discovery disabled on %s",
772 rsc->id, host_uname);
773 return EOPNOTSUPP;
774 }
775
776 if (controld_api == NULL) {
777 out->err(out, "Dry run: skipping clean-up of %s on %s due to CIB_file",
778 rsc->id, host_uname);
779 return pcmk_rc_ok;
780 }
781
782 rc = clear_rsc_fail_attrs(rsc, operation, interval_spec, node);
783 if (rc != pcmk_rc_ok) {
784 out->err(out, "Unable to clean up %s failures on %s: %s",
785 rsc->id, host_uname, pcmk_rc_str(rc));
786 return rc;
787 }
788
789 if (just_failures) {
790 rc = clear_rsc_failures(out, controld_api, host_uname, rsc->id, operation,
791 interval_spec, data_set);
792 } else {
793 rc = clear_rsc_history(controld_api, host_uname, rsc->id, data_set);
794 }
795 if (rc != pcmk_rc_ok) {
796 out->err(out, "Cleaned %s failures on %s, but unable to clean history: %s",
797 rsc->id, host_uname, pcmk_strerror(rc));
798 } else {
799 out->info(out, "Cleaned up %s on %s", rsc->id, host_uname);
800 }
801 return rc;
802 }
803
804
805 int
806 cli_cleanup_all(pcmk_ipc_api_t *controld_api, const char *node_name,
807 const char *operation, const char *interval_spec,
808 pe_working_set_t *data_set)
809 {
810 pcmk__output_t *out = data_set->priv;
811 int rc = pcmk_rc_ok;
812 int attr_options = pcmk__node_attr_none;
813 const char *display_name = node_name? node_name : "all nodes";
814
815 if (controld_api == NULL) {
816 out->info(out, "Dry run: skipping clean-up of %s due to CIB_file",
817 display_name);
818 return rc;
819 }
820
821 if (node_name) {
822 pe_node_t *node = pe_find_node(data_set->nodes, node_name);
823
824 if (node == NULL) {
825 out->err(out, "Unknown node: %s", node_name);
826 return ENXIO;
827 }
828 if (pe__is_guest_or_remote_node(node)) {
829 attr_options |= pcmk__node_attr_remote;
830 }
831 }
832
833 rc = pcmk__attrd_api_clear_failures(NULL, node_name, NULL, operation,
834 interval_spec, NULL, attr_options);
835 if (rc != pcmk_rc_ok) {
836 out->err(out, "Unable to clean up all failures on %s: %s",
837 display_name, pcmk_rc_str(rc));
838 return rc;
839 }
840
841 if (node_name) {
842 rc = clear_rsc_failures(out, controld_api, node_name, NULL,
843 operation, interval_spec, data_set);
844 if (rc != pcmk_rc_ok) {
845 out->err(out, "Cleaned all resource failures on %s, but unable to clean history: %s",
846 node_name, pcmk_strerror(rc));
847 return rc;
848 }
849 } else {
850 for (GList *iter = data_set->nodes; iter; iter = iter->next) {
851 pe_node_t *node = (pe_node_t *) iter->data;
852
853 rc = clear_rsc_failures(out, controld_api, node->details->uname, NULL,
854 operation, interval_spec, data_set);
855 if (rc != pcmk_rc_ok) {
856 out->err(out, "Cleaned all resource failures on all nodes, but unable to clean history: %s",
857 pcmk_strerror(rc));
858 return rc;
859 }
860 }
861 }
862
863 out->info(out, "Cleaned up all resources on %s", display_name);
864 return rc;
865 }
866
867 static void
868 check_role(resource_checks_t *checks)
869 {
870 const char *role_s = g_hash_table_lookup(checks->rsc->meta,
871 XML_RSC_ATTR_TARGET_ROLE);
872
873 if (role_s == NULL) {
874 return;
875 }
876 switch (text2role(role_s)) {
877 case RSC_ROLE_STOPPED:
878 checks->flags |= rsc_remain_stopped;
879 break;
880
881 case RSC_ROLE_UNPROMOTED:
882 if (pcmk_is_set(uber_parent(checks->rsc)->flags,
883 pe_rsc_promotable)) {
884 checks->flags |= rsc_unpromotable;
885 }
886 break;
887
888 default:
889 break;
890 }
891 }
892
893 static void
894 check_managed(resource_checks_t *checks)
895 {
896 const char *managed_s = g_hash_table_lookup(checks->rsc->meta,
897 XML_RSC_ATTR_MANAGED);
898
899 if ((managed_s != NULL) && !crm_is_true(managed_s)) {
900 checks->flags |= rsc_unmanaged;
901 }
902 }
903
904 static void
905 check_locked(resource_checks_t *checks)
906 {
907 if (checks->rsc->lock_node != NULL) {
908 checks->flags |= rsc_locked;
909 checks->lock_node = checks->rsc->lock_node->details->uname;
910 }
911 }
912
913 static bool
914 node_is_unhealthy(pe_node_t *node)
915 {
916 switch (pe__health_strategy(node->details->data_set)) {
917 case pcmk__health_strategy_none:
918 break;
919
920 case pcmk__health_strategy_no_red:
921 if (pe__node_health(node) < 0) {
922 return true;
923 }
924 break;
925
926 case pcmk__health_strategy_only_green:
927 if (pe__node_health(node) <= 0) {
928 return true;
929 }
930 break;
931
932 case pcmk__health_strategy_progressive:
933 case pcmk__health_strategy_custom:
934
935
936
937
938 break;
939 }
940 return false;
941 }
942
943 static void
944 check_node_health(resource_checks_t *checks, pe_node_t *node)
945 {
946 if (node == NULL) {
947 GHashTableIter iter;
948 bool allowed = false;
949 bool all_nodes_unhealthy = true;
950
951 g_hash_table_iter_init(&iter, checks->rsc->allowed_nodes);
952 while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
953 allowed = true;
954 if (!node_is_unhealthy(node)) {
955 all_nodes_unhealthy = false;
956 break;
957 }
958 }
959 if (allowed && all_nodes_unhealthy) {
960 checks->flags |= rsc_node_health;
961 }
962
963 } else if (node_is_unhealthy(node)) {
964 checks->flags |= rsc_node_health;
965 }
966 }
967
968 int
969 cli_resource_check(pcmk__output_t *out, pe_resource_t *rsc, pe_node_t *node)
970 {
971 resource_checks_t checks = { .rsc = rsc };
972
973 check_role(&checks);
974 check_managed(&checks);
975 check_locked(&checks);
976 check_node_health(&checks, node);
977
978 return out->message(out, "resource-check-list", &checks);
979 }
980
981
982 int
983 cli_resource_fail(pcmk_ipc_api_t *controld_api, const char *host_uname,
984 const char *rsc_id, pe_working_set_t *data_set)
985 {
986 crm_notice("Failing %s on %s", rsc_id, host_uname);
987 return send_lrm_rsc_op(controld_api, true, host_uname, rsc_id, data_set);
988 }
989
990 static GHashTable *
991 generate_resource_params(pe_resource_t *rsc, pe_node_t *node,
992 pe_working_set_t *data_set)
993 {
994 GHashTable *params = NULL;
995 GHashTable *meta = NULL;
996 GHashTable *combined = NULL;
997 GHashTableIter iter;
998 char *key = NULL;
999 char *value = NULL;
1000
1001 combined = pcmk__strkey_table(free, free);
1002
1003 params = pe_rsc_params(rsc, node, data_set);
1004 if (params != NULL) {
1005 g_hash_table_iter_init(&iter, params);
1006 while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
1007 g_hash_table_insert(combined, strdup(key), strdup(value));
1008 }
1009 }
1010
1011 meta = pcmk__strkey_table(free, free);
1012 get_meta_attributes(meta, rsc, node, data_set);
1013 if (meta != NULL) {
1014 g_hash_table_iter_init(&iter, meta);
1015 while (g_hash_table_iter_next(&iter, (gpointer *) & key, (gpointer *) & value)) {
1016 char *crm_name = crm_meta_name(key);
1017
1018 g_hash_table_insert(combined, crm_name, strdup(value));
1019 }
1020 g_hash_table_destroy(meta);
1021 }
1022
1023 return combined;
1024 }
1025
1026 bool resource_is_running_on(pe_resource_t *rsc, const char *host)
1027 {
1028 bool found = true;
1029 GList *hIter = NULL;
1030 GList *hosts = NULL;
1031
1032 if (rsc == NULL) {
1033 return false;
1034 }
1035
1036 rsc->fns->location(rsc, &hosts, TRUE);
1037 for (hIter = hosts; host != NULL && hIter != NULL; hIter = hIter->next) {
1038 pe_node_t *node = (pe_node_t *) hIter->data;
1039
1040 if (pcmk__strcase_any_of(host, node->details->uname, node->details->id, NULL)) {
1041 crm_trace("Resource %s is running on %s\n", rsc->id, host);
1042 goto done;
1043 }
1044 }
1045
1046 if (host != NULL) {
1047 crm_trace("Resource %s is not running on: %s\n", rsc->id, host);
1048 found = false;
1049
1050 } else if(host == NULL && hosts == NULL) {
1051 crm_trace("Resource %s is not running\n", rsc->id);
1052 found = false;
1053 }
1054
1055 done:
1056 g_list_free(hosts);
1057 return found;
1058 }
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069 static GList *
1070 get_active_resources(const char *host, GList *rsc_list)
1071 {
1072 GList *rIter = NULL;
1073 GList *active = NULL;
1074
1075 for (rIter = rsc_list; rIter != NULL; rIter = rIter->next) {
1076 pe_resource_t *rsc = (pe_resource_t *) rIter->data;
1077
1078
1079
1080
1081
1082 if (rsc->variant == pe_group) {
1083 active = g_list_concat(active,
1084 get_active_resources(host, rsc->children));
1085 } else if (resource_is_running_on(rsc, host)) {
1086 active = g_list_append(active, strdup(rsc->id));
1087 }
1088 }
1089 return active;
1090 }
1091
1092 static void dump_list(GList *items, const char *tag)
1093 {
1094 int lpc = 0;
1095 GList *item = NULL;
1096
1097 for (item = items; item != NULL; item = item->next) {
1098 crm_trace("%s[%d]: %s", tag, lpc, (char*)item->data);
1099 lpc++;
1100 }
1101 }
1102
1103 static void display_list(pcmk__output_t *out, GList *items, const char *tag)
1104 {
1105 GList *item = NULL;
1106
1107 for (item = items; item != NULL; item = item->next) {
1108 out->info(out, "%s%s", tag, (const char *)item->data);
1109 }
1110 }
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128 int
1129 update_working_set_xml(pe_working_set_t *data_set, xmlNode **xml)
1130 {
1131 if (cli_config_update(xml, NULL, FALSE) == FALSE) {
1132 return ENOKEY;
1133 }
1134 data_set->input = *xml;
1135 data_set->now = crm_time_new(NULL);
1136 return pcmk_rc_ok;
1137 }
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150 static int
1151 update_working_set_from_cib(pcmk__output_t *out, pe_working_set_t * data_set,
1152 cib_t *cib)
1153 {
1154 xmlNode *cib_xml_copy = NULL;
1155 int rc = pcmk_rc_ok;
1156
1157 rc = cib->cmds->query(cib, NULL, &cib_xml_copy, cib_scope_local | cib_sync_call);
1158 rc = pcmk_legacy2rc(rc);
1159
1160 if (rc != pcmk_rc_ok) {
1161 out->err(out, "Could not obtain the current CIB: %s (%d)", pcmk_strerror(rc), rc);
1162 return rc;
1163 }
1164 rc = update_working_set_xml(data_set, &cib_xml_copy);
1165 if (rc != pcmk_rc_ok) {
1166 out->err(out, "Could not upgrade the current CIB XML");
1167 free_xml(cib_xml_copy);
1168 return rc;
1169 }
1170
1171 return rc;
1172 }
1173
1174
1175 static int
1176 update_dataset(cib_t *cib, pe_working_set_t * data_set, bool simulate)
1177 {
1178 char *pid = NULL;
1179 char *shadow_file = NULL;
1180 cib_t *shadow_cib = NULL;
1181 int rc = pcmk_rc_ok;
1182
1183 pcmk__output_t *out = data_set->priv;
1184
1185 pe_reset_working_set(data_set);
1186 pe__set_working_set_flags(data_set, pe_flag_no_counts|pe_flag_no_compat);
1187 rc = update_working_set_from_cib(out, data_set, cib);
1188 if (rc != pcmk_rc_ok) {
1189 return rc;
1190 }
1191
1192 if(simulate) {
1193 bool prev_quiet = false;
1194
1195 pid = pcmk__getpid_s();
1196 shadow_cib = cib_shadow_new(pid);
1197 shadow_file = get_shadow_file(pid);
1198
1199 if (shadow_cib == NULL) {
1200 out->err(out, "Could not create shadow cib: '%s'", pid);
1201 rc = ENXIO;
1202 goto done;
1203 }
1204
1205 rc = write_xml_file(data_set->input, shadow_file, FALSE);
1206
1207 if (rc < 0) {
1208 out->err(out, "Could not populate shadow cib: %s (%d)", pcmk_strerror(rc), rc);
1209 goto done;
1210 }
1211
1212 rc = shadow_cib->cmds->signon(shadow_cib, crm_system_name, cib_command);
1213 rc = pcmk_legacy2rc(rc);
1214
1215 if (rc != pcmk_rc_ok) {
1216 out->err(out, "Could not connect to shadow cib: %s (%d)", pcmk_strerror(rc), rc);
1217 goto done;
1218 }
1219
1220 pcmk__schedule_actions(data_set->input,
1221 pe_flag_no_counts|pe_flag_no_compat, data_set);
1222
1223 prev_quiet = out->is_quiet(out);
1224 out->quiet = true;
1225 pcmk__simulate_transition(data_set, shadow_cib, NULL);
1226 out->quiet = prev_quiet;
1227
1228 rc = update_dataset(shadow_cib, data_set, false);
1229
1230 } else {
1231 cluster_status(data_set);
1232 }
1233
1234 done:
1235
1236 cib_delete(shadow_cib);
1237 free(pid);
1238
1239 if(shadow_file) {
1240 unlink(shadow_file);
1241 free(shadow_file);
1242 }
1243
1244 return rc;
1245 }
1246
1247 static int
1248 max_delay_for_resource(pe_working_set_t * data_set, pe_resource_t *rsc)
1249 {
1250 int delay = 0;
1251 int max_delay = 0;
1252
1253 if(rsc && rsc->children) {
1254 GList *iter = NULL;
1255
1256 for(iter = rsc->children; iter; iter = iter->next) {
1257 pe_resource_t *child = (pe_resource_t *)iter->data;
1258
1259 delay = max_delay_for_resource(data_set, child);
1260 if(delay > max_delay) {
1261 double seconds = delay / 1000.0;
1262 crm_trace("Calculated new delay of %.1fs due to %s", seconds, child->id);
1263 max_delay = delay;
1264 }
1265 }
1266
1267 } else if(rsc) {
1268 char *key = crm_strdup_printf("%s_%s_0", rsc->id, RSC_STOP);
1269 pe_action_t *stop = custom_action(rsc, key, RSC_STOP, NULL, TRUE, FALSE, data_set);
1270 const char *value = g_hash_table_lookup(stop->meta, XML_ATTR_TIMEOUT);
1271 long long result_ll;
1272
1273 if ((pcmk__scan_ll(value, &result_ll, -1LL) == pcmk_rc_ok)
1274 && (result_ll >= 0) && (result_ll <= INT_MAX)) {
1275 max_delay = (int) result_ll;
1276 } else {
1277 max_delay = -1;
1278 }
1279 pe_free_action(stop);
1280 }
1281
1282 return max_delay;
1283 }
1284
1285 static int
1286 max_delay_in(pe_working_set_t * data_set, GList *resources)
1287 {
1288 int max_delay = 0;
1289 GList *item = NULL;
1290
1291 for (item = resources; item != NULL; item = item->next) {
1292 int delay = 0;
1293 pe_resource_t *rsc = pe_find_resource(data_set->resources, (const char *)item->data);
1294
1295 delay = max_delay_for_resource(data_set, rsc);
1296
1297 if(delay > max_delay) {
1298 double seconds = delay / 1000.0;
1299 crm_trace("Calculated new delay of %.1fs due to %s", seconds, rsc->id);
1300 max_delay = delay;
1301 }
1302 }
1303
1304 return 5 + (max_delay / 1000);
1305 }
1306
1307 #define waiting_for_starts(d, r, h) ((d != NULL) || \
1308 (!resource_is_running_on((r), (h))))
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324 int
1325 cli_resource_restart(pcmk__output_t *out, pe_resource_t *rsc, pe_node_t *node,
1326 const char *move_lifetime, int timeout_ms, cib_t *cib,
1327 int cib_options, gboolean promoted_role_only, gboolean force)
1328 {
1329 int rc = pcmk_rc_ok;
1330 int lpc = 0;
1331 int before = 0;
1332 int step_timeout_s = 0;
1333 int sleep_interval = 2;
1334 int timeout = timeout_ms / 1000;
1335
1336 bool stop_via_ban = false;
1337 char *rsc_id = NULL;
1338 char *lookup_id = NULL;
1339 char *orig_target_role = NULL;
1340
1341 GList *list_delta = NULL;
1342 GList *target_active = NULL;
1343 GList *current_active = NULL;
1344 GList *restart_target_active = NULL;
1345
1346 pe_working_set_t *data_set = NULL;
1347 pe_resource_t *parent = uber_parent(rsc);
1348
1349 bool running = false;
1350 const char *id = rsc->clone_name ? rsc->clone_name : rsc->id;
1351 const char *host = node ? node->details->uname : NULL;
1352
1353
1354
1355
1356 if (pe_rsc_is_bundled(rsc)) {
1357 rsc = parent->parent;
1358 }
1359
1360 running = resource_is_running_on(rsc, host);
1361
1362 if (pe_rsc_is_clone(parent) && !running) {
1363 if (pe_rsc_is_unique_clone(parent)) {
1364 lookup_id = strdup(rsc->id);
1365 } else {
1366 lookup_id = clone_strip(rsc->id);
1367 }
1368
1369 rsc = parent->fns->find_rsc(parent, lookup_id, node, pe_find_any|pe_find_current);
1370 free(lookup_id);
1371 running = resource_is_running_on(rsc, host);
1372 }
1373
1374 if (!running) {
1375 if (host) {
1376 out->err(out, "%s is not running on %s and so cannot be restarted", id, host);
1377 } else {
1378 out->err(out, "%s is not running anywhere and so cannot be restarted", id);
1379 }
1380 return ENXIO;
1381 }
1382
1383 rsc_id = strdup(rsc->id);
1384
1385 if (pe_rsc_is_unique_clone(parent)) {
1386 lookup_id = strdup(rsc->id);
1387 } else {
1388 lookup_id = clone_strip(rsc->id);
1389 }
1390
1391 if (host) {
1392 if (pe_rsc_is_clone(rsc) || pe_bundle_replicas(rsc)) {
1393 stop_via_ban = true;
1394 } else if (pe_rsc_is_clone(parent)) {
1395 stop_via_ban = true;
1396 free(lookup_id);
1397 lookup_id = strdup(parent->id);
1398 }
1399 }
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419 data_set = pe_new_working_set();
1420 if (data_set == NULL) {
1421 crm_perror(LOG_ERR, "Could not allocate working set");
1422 rc = ENOMEM;
1423 goto done;
1424 }
1425
1426 data_set->priv = out;
1427 rc = update_dataset(cib, data_set, false);
1428
1429 if(rc != pcmk_rc_ok) {
1430 out->err(out, "Could not get new resource list: %s (%d)", pcmk_strerror(rc), rc);
1431 goto done;
1432 }
1433
1434 restart_target_active = get_active_resources(host, data_set->resources);
1435 current_active = get_active_resources(host, data_set->resources);
1436
1437 dump_list(current_active, "Origin");
1438
1439 if (stop_via_ban) {
1440
1441 out->quiet = true;
1442 rc = cli_resource_ban(out, lookup_id, host, move_lifetime, NULL, cib,
1443 cib_options, promoted_role_only);
1444
1445 } else {
1446
1447
1448
1449
1450
1451 find_resource_attr(out, cib, XML_NVPAIR_ATTR_VALUE, lookup_id, NULL, NULL,
1452 NULL, XML_RSC_ATTR_TARGET_ROLE, &orig_target_role);
1453 rc = cli_resource_update_attribute(rsc, rsc_id, NULL, XML_TAG_META_SETS,
1454 NULL, XML_RSC_ATTR_TARGET_ROLE,
1455 RSC_STOPPED, FALSE, cib, cib_options,
1456 data_set, force);
1457 }
1458 if(rc != pcmk_rc_ok) {
1459 out->err(out, "Could not set target-role for %s: %s (%d)", rsc_id, pcmk_strerror(rc), rc);
1460 if (current_active != NULL) {
1461 g_list_free_full(current_active, free);
1462 current_active = NULL;
1463 }
1464 if (restart_target_active != NULL) {
1465 g_list_free_full(restart_target_active, free);
1466 restart_target_active = NULL;
1467 }
1468 goto done;
1469 }
1470
1471 rc = update_dataset(cib, data_set, true);
1472 if(rc != pcmk_rc_ok) {
1473 out->err(out, "Could not determine which resources would be stopped");
1474 goto failure;
1475 }
1476
1477 target_active = get_active_resources(host, data_set->resources);
1478 dump_list(target_active, "Target");
1479
1480 list_delta = pcmk__subtract_lists(current_active, target_active, (GCompareFunc) strcmp);
1481 out->info(out, "Waiting for %d resources to stop:", g_list_length(list_delta));
1482 display_list(out, list_delta, " * ");
1483
1484 step_timeout_s = timeout / sleep_interval;
1485 while (list_delta != NULL) {
1486 before = g_list_length(list_delta);
1487 if(timeout_ms == 0) {
1488 step_timeout_s = max_delay_in(data_set, list_delta) / sleep_interval;
1489 }
1490
1491
1492 for(lpc = 0; (lpc < step_timeout_s) && (list_delta != NULL); lpc++) {
1493 sleep(sleep_interval);
1494 if(timeout) {
1495 timeout -= sleep_interval;
1496 crm_trace("%ds remaining", timeout);
1497 }
1498 rc = update_dataset(cib, data_set, FALSE);
1499 if(rc != pcmk_rc_ok) {
1500 out->err(out, "Could not determine which resources were stopped");
1501 goto failure;
1502 }
1503
1504 if (current_active != NULL) {
1505 g_list_free_full(current_active, free);
1506 current_active = NULL;
1507 }
1508 current_active = get_active_resources(host, data_set->resources);
1509 g_list_free(list_delta);
1510 list_delta = NULL;
1511 list_delta = pcmk__subtract_lists(current_active, target_active, (GCompareFunc) strcmp);
1512 dump_list(current_active, "Current");
1513 dump_list(list_delta, "Delta");
1514 }
1515
1516 crm_trace("%d (was %d) resources remaining", g_list_length(list_delta), before);
1517 if(before == g_list_length(list_delta)) {
1518
1519 out->err(out, "Could not complete shutdown of %s, %d resources remaining", rsc_id, g_list_length(list_delta));
1520 display_list(out, list_delta, " * ");
1521 rc = ETIME;
1522 goto failure;
1523 }
1524
1525 }
1526
1527 if (stop_via_ban) {
1528 rc = cli_resource_clear(lookup_id, host, NULL, cib, cib_options, true, force);
1529
1530 } else if (orig_target_role) {
1531 rc = cli_resource_update_attribute(rsc, rsc_id, NULL, XML_TAG_META_SETS,
1532 NULL, XML_RSC_ATTR_TARGET_ROLE,
1533 orig_target_role, FALSE, cib,
1534 cib_options, data_set, force);
1535 free(orig_target_role);
1536 orig_target_role = NULL;
1537 } else {
1538 rc = cli_resource_delete_attribute(rsc, rsc_id, NULL, XML_TAG_META_SETS,
1539 NULL, XML_RSC_ATTR_TARGET_ROLE, cib,
1540 cib_options, data_set, force);
1541 }
1542
1543 if(rc != pcmk_rc_ok) {
1544 out->err(out, "Could not unset target-role for %s: %s (%d)", rsc_id, pcmk_strerror(rc), rc);
1545 goto done;
1546 }
1547
1548 if (target_active != NULL) {
1549 g_list_free_full(target_active, free);
1550 target_active = NULL;
1551 }
1552 target_active = restart_target_active;
1553 list_delta = pcmk__subtract_lists(target_active, current_active, (GCompareFunc) strcmp);
1554 out->info(out, "Waiting for %d resources to start again:", g_list_length(list_delta));
1555 display_list(out, list_delta, " * ");
1556
1557 step_timeout_s = timeout / sleep_interval;
1558 while (waiting_for_starts(list_delta, rsc, host)) {
1559 before = g_list_length(list_delta);
1560 if(timeout_ms == 0) {
1561 step_timeout_s = max_delay_in(data_set, list_delta) / sleep_interval;
1562 }
1563
1564
1565 for (lpc = 0; (lpc < step_timeout_s) && waiting_for_starts(list_delta, rsc, host); lpc++) {
1566
1567 sleep(sleep_interval);
1568 if(timeout) {
1569 timeout -= sleep_interval;
1570 crm_trace("%ds remaining", timeout);
1571 }
1572
1573 rc = update_dataset(cib, data_set, false);
1574 if(rc != pcmk_rc_ok) {
1575 out->err(out, "Could not determine which resources were started");
1576 goto failure;
1577 }
1578
1579 if (current_active != NULL) {
1580 g_list_free_full(current_active, free);
1581 current_active = NULL;
1582 }
1583
1584
1585
1586
1587 current_active = get_active_resources(NULL, data_set->resources);
1588 g_list_free(list_delta);
1589 list_delta = pcmk__subtract_lists(target_active, current_active, (GCompareFunc) strcmp);
1590 dump_list(current_active, "Current");
1591 dump_list(list_delta, "Delta");
1592 }
1593
1594 if(before == g_list_length(list_delta)) {
1595
1596 out->err(out, "Could not complete restart of %s, %d resources remaining", rsc_id, g_list_length(list_delta));
1597 display_list(out, list_delta, " * ");
1598 rc = ETIME;
1599 goto failure;
1600 }
1601
1602 }
1603
1604 rc = pcmk_rc_ok;
1605 goto done;
1606
1607 failure:
1608 if (stop_via_ban) {
1609 cli_resource_clear(lookup_id, host, NULL, cib, cib_options, true, force);
1610 } else if (orig_target_role) {
1611 cli_resource_update_attribute(rsc, rsc_id, NULL, XML_TAG_META_SETS, NULL,
1612 XML_RSC_ATTR_TARGET_ROLE, orig_target_role,
1613 FALSE, cib, cib_options, data_set, force);
1614 free(orig_target_role);
1615 } else {
1616 cli_resource_delete_attribute(rsc, rsc_id, NULL, XML_TAG_META_SETS, NULL,
1617 XML_RSC_ATTR_TARGET_ROLE, cib, cib_options,
1618 data_set, force);
1619 }
1620
1621 done:
1622 if (list_delta != NULL) {
1623 g_list_free(list_delta);
1624 }
1625 if (current_active != NULL) {
1626 g_list_free_full(current_active, free);
1627 }
1628 if (target_active != NULL && (target_active != restart_target_active)) {
1629 g_list_free_full(target_active, free);
1630 }
1631 if (restart_target_active != NULL) {
1632 g_list_free_full(restart_target_active, free);
1633 }
1634 free(rsc_id);
1635 free(lookup_id);
1636 pe_free_working_set(data_set);
1637 return rc;
1638 }
1639
1640 static inline bool action_is_pending(pe_action_t *action)
1641 {
1642 if (pcmk_any_flags_set(action->flags, pe_action_optional|pe_action_pseudo)
1643 || !pcmk_is_set(action->flags, pe_action_runnable)
1644 || pcmk__str_eq("notify", action->task, pcmk__str_casei)) {
1645 return false;
1646 }
1647 return true;
1648 }
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658 static bool
1659 actions_are_pending(GList *actions)
1660 {
1661 GList *action;
1662
1663 for (action = actions; action != NULL; action = action->next) {
1664 pe_action_t *a = (pe_action_t *)action->data;
1665 if (action_is_pending(a)) {
1666 crm_notice("Waiting for %s (flags=%#.8x)", a->uuid, a->flags);
1667 return true;
1668 }
1669 }
1670 return false;
1671 }
1672
1673 static void
1674 print_pending_actions(pcmk__output_t *out, GList *actions)
1675 {
1676 GList *action;
1677
1678 out->info(out, "Pending actions:");
1679 for (action = actions; action != NULL; action = action->next) {
1680 pe_action_t *a = (pe_action_t *) action->data;
1681
1682 if (!action_is_pending(a)) {
1683 continue;
1684 }
1685
1686 if (a->node) {
1687 out->info(out, "\tAction %d: %s\ton %s",
1688 a->id, a->uuid, pe__node_name(a->node));
1689 } else {
1690 out->info(out, "\tAction %d: %s", a->id, a->uuid);
1691 }
1692 }
1693 }
1694
1695
1696 #define WAIT_DEFAULT_TIMEOUT_S (60 * 60)
1697
1698
1699 #define WAIT_SLEEP_S (2)
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715 int
1716 wait_till_stable(pcmk__output_t *out, int timeout_ms, cib_t * cib)
1717 {
1718 pe_working_set_t *data_set = NULL;
1719 int rc = pcmk_rc_ok;
1720 int timeout_s = timeout_ms? ((timeout_ms + 999) / 1000) : WAIT_DEFAULT_TIMEOUT_S;
1721 time_t expire_time = time(NULL) + timeout_s;
1722 time_t time_diff;
1723 bool printed_version_warning = out->is_quiet(out);
1724
1725 data_set = pe_new_working_set();
1726 if (data_set == NULL) {
1727 return ENOMEM;
1728 }
1729
1730 do {
1731
1732
1733 time_diff = expire_time - time(NULL);
1734 if (time_diff > 0) {
1735 crm_info("Waiting up to %lld seconds for cluster actions to complete", (long long) time_diff);
1736 } else {
1737 print_pending_actions(out, data_set->actions);
1738 pe_free_working_set(data_set);
1739 return ETIME;
1740 }
1741 if (rc == pcmk_rc_ok) {
1742 sleep(WAIT_SLEEP_S);
1743 }
1744
1745
1746 pe_reset_working_set(data_set);
1747 rc = update_working_set_from_cib(out, data_set, cib);
1748 if (rc != pcmk_rc_ok) {
1749 pe_free_working_set(data_set);
1750 return rc;
1751 }
1752 pcmk__schedule_actions(data_set->input,
1753 pe_flag_no_counts|pe_flag_no_compat, data_set);
1754
1755 if (!printed_version_warning) {
1756
1757
1758
1759
1760
1761
1762
1763
1764 const char *dc_version = g_hash_table_lookup(data_set->config_hash,
1765 "dc-version");
1766
1767 if (!pcmk__str_eq(dc_version, PACEMAKER_VERSION "-" BUILD_VERSION, pcmk__str_casei)) {
1768 out->info(out, "warning: wait option may not work properly in "
1769 "mixed-version cluster");
1770 printed_version_warning = true;
1771 }
1772 }
1773
1774 } while (actions_are_pending(data_set->actions));
1775
1776 pe_free_working_set(data_set);
1777 return rc;
1778 }
1779
1780 static const char *
1781 get_action(const char *rsc_action) {
1782 const char *action = NULL;
1783
1784 if (pcmk__str_eq(rsc_action, "validate", pcmk__str_casei)) {
1785 action = "validate-all";
1786
1787 } else if (pcmk__str_eq(rsc_action, "force-check", pcmk__str_casei)) {
1788 action = "monitor";
1789
1790 } else if (pcmk__strcase_any_of(rsc_action, "force-start", "force-stop",
1791 "force-demote", "force-promote", NULL)) {
1792 action = rsc_action+6;
1793 } else {
1794 action = rsc_action;
1795 }
1796
1797 return action;
1798 }
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813 static void
1814 set_agent_environment(GHashTable *params, int timeout_ms, int check_level,
1815 int verbosity)
1816 {
1817 g_hash_table_insert(params, strdup("CRM_meta_timeout"),
1818 crm_strdup_printf("%d", timeout_ms));
1819
1820 g_hash_table_insert(params, strdup(XML_ATTR_CRM_VERSION),
1821 strdup(CRM_FEATURE_SET));
1822
1823 if (check_level >= 0) {
1824 char *level = crm_strdup_printf("%d", check_level);
1825
1826 setenv("OCF_CHECK_LEVEL", level, 1);
1827 free(level);
1828 }
1829
1830 setenv("HA_debug", (verbosity > 0)? "1" : "0", 1);
1831 if (verbosity > 1) {
1832 setenv("OCF_TRACE_RA", "1", 1);
1833 }
1834
1835
1836
1837
1838
1839 setenv("OCF_TRACE_FILE", "/dev/stderr", 0);
1840 }
1841
1842
1843
1844
1845
1846
1847
1848
1849 static void
1850 apply_overrides(GHashTable *params, GHashTable *overrides)
1851 {
1852 if (overrides != NULL) {
1853 GHashTableIter iter;
1854 char *name = NULL;
1855 char *value = NULL;
1856
1857 g_hash_table_iter_init(&iter, overrides);
1858 while (g_hash_table_iter_next(&iter, (gpointer *) &name,
1859 (gpointer *) &value)) {
1860 g_hash_table_replace(params, strdup(name), strdup(value));
1861 }
1862 }
1863 }
1864
1865 crm_exit_t
1866 cli_resource_execute_from_params(pcmk__output_t *out, const char *rsc_name,
1867 const char *rsc_class, const char *rsc_prov,
1868 const char *rsc_type, const char *rsc_action,
1869 GHashTable *params, GHashTable *override_hash,
1870 int timeout_ms, int resource_verbose, gboolean force,
1871 int check_level)
1872 {
1873 const char *class = rsc_class;
1874 const char *action = get_action(rsc_action);
1875 crm_exit_t exit_code = CRM_EX_OK;
1876 svc_action_t *op = NULL;
1877
1878
1879 if (timeout_ms == 0) {
1880 timeout_ms = crm_get_msec(CRM_DEFAULT_OP_TIMEOUT_S);
1881 }
1882
1883 set_agent_environment(params, timeout_ms, check_level, resource_verbose);
1884 apply_overrides(params, override_hash);
1885
1886 op = services__create_resource_action(rsc_name? rsc_name : "test",
1887 rsc_class, rsc_prov, rsc_type, action,
1888 0, timeout_ms, params, 0);
1889 if (op == NULL) {
1890 out->err(out, "Could not execute %s using %s%s%s:%s: %s",
1891 action, rsc_class, (rsc_prov? ":" : ""),
1892 (rsc_prov? rsc_prov : ""), rsc_type, strerror(ENOMEM));
1893 g_hash_table_destroy(params);
1894 return CRM_EX_OSERR;
1895 }
1896
1897 if (pcmk__str_eq(rsc_class, PCMK_RESOURCE_CLASS_SERVICE, pcmk__str_casei)) {
1898 class = resources_find_service_class(rsc_type);
1899 }
1900 if (!pcmk__strcase_any_of(class, PCMK_RESOURCE_CLASS_OCF,
1901 PCMK_RESOURCE_CLASS_LSB, NULL)) {
1902 services__format_result(op, CRM_EX_UNIMPLEMENT_FEATURE, PCMK_EXEC_ERROR,
1903 "Manual execution of the %s standard is "
1904 "unsupported", pcmk__s(class, "unspecified"));
1905 }
1906
1907 if (op->rc != PCMK_OCF_UNKNOWN) {
1908 exit_code = op->rc;
1909 goto done;
1910 }
1911
1912 services_action_sync(op);
1913
1914
1915 {
1916 enum ocf_exitcode ocf_code = services_result2ocf(class, action, op->rc);
1917
1918
1919 exit_code = (crm_exit_t) ocf_code;
1920 }
1921
1922 done:
1923 out->message(out, "resource-agent-action", resource_verbose, rsc_class,
1924 rsc_prov, rsc_type, rsc_name, rsc_action, override_hash,
1925 exit_code, op->status, services__exit_reason(op),
1926 op->stdout_data, op->stderr_data);
1927 services_action_free(op);
1928 return exit_code;
1929 }
1930
1931 crm_exit_t
1932 cli_resource_execute(pe_resource_t *rsc, const char *requested_name,
1933 const char *rsc_action, GHashTable *override_hash,
1934 int timeout_ms, cib_t * cib, pe_working_set_t *data_set,
1935 int resource_verbose, gboolean force, int check_level)
1936 {
1937 pcmk__output_t *out = data_set->priv;
1938 crm_exit_t exit_code = CRM_EX_OK;
1939 const char *rid = NULL;
1940 const char *rtype = NULL;
1941 const char *rprov = NULL;
1942 const char *rclass = NULL;
1943 GHashTable *params = NULL;
1944
1945 if (pcmk__strcase_any_of(rsc_action, "force-start", "force-demote",
1946 "force-promote", NULL)) {
1947 if(pe_rsc_is_clone(rsc)) {
1948 GList *nodes = cli_resource_search(rsc, requested_name, data_set);
1949 if(nodes != NULL && force == FALSE) {
1950 out->err(out, "It is not safe to %s %s here: the cluster claims it is already active",
1951 rsc_action, rsc->id);
1952 out->err(out, "Try setting target-role=Stopped first or specifying "
1953 "the force option");
1954 return CRM_EX_UNSAFE;
1955 }
1956
1957 g_list_free_full(nodes, free);
1958 }
1959 }
1960
1961 if(pe_rsc_is_clone(rsc)) {
1962
1963 rsc = rsc->children->data;
1964 }
1965
1966 if(rsc->variant == pe_group) {
1967 out->err(out, "Sorry, the %s option doesn't support group resources", rsc_action);
1968 return CRM_EX_UNIMPLEMENT_FEATURE;
1969 } else if (rsc->variant == pe_container || pe_rsc_is_bundled(rsc)) {
1970 out->err(out, "Sorry, the %s option doesn't support bundled resources", rsc_action);
1971 return CRM_EX_UNIMPLEMENT_FEATURE;
1972 }
1973
1974 rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
1975 rprov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
1976 rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE);
1977
1978 params = generate_resource_params(rsc, NULL ,
1979 data_set);
1980
1981 if (timeout_ms == 0) {
1982 timeout_ms = pe_get_configured_timeout(rsc, get_action(rsc_action), data_set);
1983 }
1984
1985 rid = pe_rsc_is_anon_clone(rsc->parent)? requested_name : rsc->id;
1986
1987 exit_code = cli_resource_execute_from_params(out, rid, rclass, rprov, rtype, rsc_action,
1988 params, override_hash, timeout_ms,
1989 resource_verbose, force, check_level);
1990 return exit_code;
1991 }
1992
1993
1994 int
1995 cli_resource_move(pe_resource_t *rsc, const char *rsc_id, const char *host_name,
1996 const char *move_lifetime, cib_t *cib, int cib_options,
1997 pe_working_set_t *data_set, gboolean promoted_role_only,
1998 gboolean force)
1999 {
2000 pcmk__output_t *out = data_set->priv;
2001 int rc = pcmk_rc_ok;
2002 unsigned int count = 0;
2003 pe_node_t *current = NULL;
2004 pe_node_t *dest = pe_find_node(data_set->nodes, host_name);
2005 bool cur_is_dest = false;
2006
2007 if (dest == NULL) {
2008 return pcmk_rc_node_unknown;
2009 }
2010
2011 if (promoted_role_only && !pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
2012 pe_resource_t *p = uber_parent(rsc);
2013
2014 if (pcmk_is_set(p->flags, pe_rsc_promotable)) {
2015 out->info(out, "Using parent '%s' for move instead of '%s'.", rsc->id, rsc_id);
2016 rsc_id = p->id;
2017 rsc = p;
2018
2019 } else {
2020 out->info(out, "Ignoring --promoted option: %s is not promotable",
2021 rsc_id);
2022 promoted_role_only = FALSE;
2023 }
2024 }
2025
2026 current = pe__find_active_requires(rsc, &count);
2027
2028 if (pcmk_is_set(rsc->flags, pe_rsc_promotable)) {
2029 GList *iter = NULL;
2030 unsigned int promoted_count = 0;
2031 pe_node_t *promoted_node = NULL;
2032
2033 for(iter = rsc->children; iter; iter = iter->next) {
2034 pe_resource_t *child = (pe_resource_t *)iter->data;
2035 enum rsc_role_e child_role = child->fns->state(child, TRUE);
2036
2037 if (child_role == RSC_ROLE_PROMOTED) {
2038 rsc = child;
2039 promoted_node = pe__current_node(child);
2040 promoted_count++;
2041 }
2042 }
2043 if (promoted_role_only || (promoted_count != 0)) {
2044 count = promoted_count;
2045 current = promoted_node;
2046 }
2047
2048 }
2049
2050 if (count > 1) {
2051 if (pe_rsc_is_clone(rsc)) {
2052 current = NULL;
2053 } else {
2054 return pcmk_rc_multiple;
2055 }
2056 }
2057
2058 if (current && (current->details == dest->details)) {
2059 cur_is_dest = true;
2060 if (force) {
2061 crm_info("%s is already %s on %s, reinforcing placement with location constraint.",
2062 rsc_id, promoted_role_only?"promoted":"active",
2063 pe__node_name(dest));
2064 } else {
2065 return pcmk_rc_already;
2066 }
2067 }
2068
2069
2070 cli_resource_clear(rsc_id, NULL, data_set->nodes, cib, cib_options, false, force);
2071
2072
2073 cli_resource_clear(rsc_id, dest->details->uname, data_set->nodes, cib,
2074 cib_options, TRUE, force);
2075
2076
2077 rc = cli_resource_prefer(out, rsc_id, dest->details->uname, move_lifetime,
2078 cib, cib_options, promoted_role_only);
2079
2080 crm_trace("%s%s now prefers %s%s",
2081 rsc->id, (promoted_role_only? " (promoted)" : ""),
2082 pe__node_name(dest), force?"(forced)":"");
2083
2084
2085
2086
2087 if (force && !cur_is_dest) {
2088
2089 if(current) {
2090 (void)cli_resource_ban(out, rsc_id, current->details->uname, move_lifetime,
2091 NULL, cib, cib_options, promoted_role_only);
2092
2093 } else if(count > 1) {
2094 out->info(out, "Resource '%s' is currently %s in %d locations. "
2095 "One may now move to %s",
2096 rsc_id, (promoted_role_only? "promoted" : "active"),
2097 count, pe__node_name(dest));
2098 out->info(out, "To prevent '%s' from being %s at a specific location, "
2099 "specify a node.",
2100 rsc_id, (promoted_role_only? "promoted" : "active"));
2101
2102 } else {
2103 crm_trace("Not banning %s from its current location: not active", rsc_id);
2104 }
2105 }
2106
2107 return rc;
2108 }