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