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