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