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