1 /*
2 * Copyright 2004-2018 Andrew Beekhof <andrew@beekhof.net>
3 *
4 * This source code is licensed under the GNU Lesser General Public License
5 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
6 */
7
8 #include <crm_internal.h>
9
10 #include <crm/pengine/rules.h>
11 #include <crm/pengine/status.h>
12 #include <crm/pengine/complex.h>
13 #include <crm/pengine/internal.h>
14 #include <unpack.h>
15 #include <crm/msg_xml.h>
16 #include <pe_status_private.h>
17
18 #define VARIANT_NATIVE 1
19 #include "./variant.h"
20
21 /*!
22 * \internal
23 * \brief Check whether a resource is active on multiple nodes
24 */
25 static bool
is_multiply_active(pe_resource_t * rsc)26 is_multiply_active(pe_resource_t *rsc)
27 {
28 unsigned int count = 0;
29
30 if (rsc->variant == pe_native) {
31 pe__find_active_requires(rsc, &count);
32 }
33 return count > 1;
34 }
35
36 static void
native_priority_to_node(pe_resource_t * rsc,pe_node_t * node)37 native_priority_to_node(pe_resource_t * rsc, pe_node_t * node)
38 {
39 int priority = 0;
40
41 if (rsc->priority == 0) {
42 return;
43 }
44
45 if (rsc->role == RSC_ROLE_MASTER) {
46 // Promoted instance takes base priority + 1
47 priority = rsc->priority + 1;
48
49 } else {
50 priority = rsc->priority;
51 }
52
53 node->details->priority += priority;
54 pe_rsc_trace(rsc, "Node '%s' now has priority %d with %s'%s' (priority: %d%s)",
55 node->details->uname, node->details->priority,
56 rsc->role == RSC_ROLE_MASTER ? "promoted " : "",
57 rsc->id, rsc->priority,
58 rsc->role == RSC_ROLE_MASTER ? " + 1" : "");
59
60 /* Priority of a resource running on a guest node is added to the cluster
61 * node as well. */
62 if (node->details->remote_rsc
63 && node->details->remote_rsc->container) {
64 GListPtr gIter = node->details->remote_rsc->container->running_on;
65
66 for (; gIter != NULL; gIter = gIter->next) {
67 pe_node_t *a_node = gIter->data;
68
69 a_node->details->priority += priority;
70 pe_rsc_trace(rsc, "Node '%s' now has priority %d with %s'%s' (priority: %d%s) "
71 "from guest node '%s'",
72 a_node->details->uname, a_node->details->priority,
73 rsc->role == RSC_ROLE_MASTER ? "promoted " : "",
74 rsc->id, rsc->priority,
75 rsc->role == RSC_ROLE_MASTER ? " + 1" : "",
76 node->details->uname);
77 }
78 }
79 }
80
81 void
native_add_running(resource_t * rsc,node_t * node,pe_working_set_t * data_set)82 native_add_running(resource_t * rsc, node_t * node, pe_working_set_t * data_set)
83 {
84 GListPtr gIter = rsc->running_on;
85
86 CRM_CHECK(node != NULL, return);
87 for (; gIter != NULL; gIter = gIter->next) {
88 node_t *a_node = (node_t *) gIter->data;
89
90 CRM_CHECK(a_node != NULL, return);
91 if (safe_str_eq(a_node->details->id, node->details->id)) {
92 return;
93 }
94 }
95
96 pe_rsc_trace(rsc, "Adding %s to %s %s", rsc->id, node->details->uname,
97 is_set(rsc->flags, pe_rsc_managed)?"":"(unmanaged)");
98
99 rsc->running_on = g_list_append(rsc->running_on, node);
100 if (rsc->variant == pe_native) {
101 node->details->running_rsc = g_list_append(node->details->running_rsc, rsc);
102
103 native_priority_to_node(rsc, node);
104 }
105
106 if (rsc->variant == pe_native && node->details->maintenance) {
107 clear_bit(rsc->flags, pe_rsc_managed);
108 }
109
110 if (is_not_set(rsc->flags, pe_rsc_managed)) {
111 resource_t *p = rsc->parent;
112
113 pe_rsc_info(rsc, "resource %s isn't managed", rsc->id);
114 resource_location(rsc, node, INFINITY, "not_managed_default", data_set);
115
116 while(p && node->details->online) {
117 /* add without the additional location constraint */
118 p->running_on = g_list_append(p->running_on, node);
119 p = p->parent;
120 }
121 return;
122 }
123
124 if (is_multiply_active(rsc)) {
125 switch (rsc->recovery_type) {
126 case recovery_stop_only:
127 {
128 GHashTableIter gIter;
129 node_t *local_node = NULL;
130
131 /* make sure it doesn't come up again */
132 if (rsc->allowed_nodes != NULL) {
133 g_hash_table_destroy(rsc->allowed_nodes);
134 }
135 rsc->allowed_nodes = node_hash_from_list(data_set->nodes);
136 g_hash_table_iter_init(&gIter, rsc->allowed_nodes);
137 while (g_hash_table_iter_next(&gIter, NULL, (void **)&local_node)) {
138 local_node->weight = -INFINITY;
139 }
140 }
141 break;
142 case recovery_stop_start:
143 break;
144 case recovery_block:
145 clear_bit(rsc->flags, pe_rsc_managed);
146 set_bit(rsc->flags, pe_rsc_block);
147
148 /* If the resource belongs to a group or bundle configured with
149 * multiple-active=block, block the entire entity.
150 */
151 if (rsc->parent
152 && (rsc->parent->variant == pe_group || rsc->parent->variant == pe_container)
153 && rsc->parent->recovery_type == recovery_block) {
154 GListPtr gIter = rsc->parent->children;
155
156 for (; gIter != NULL; gIter = gIter->next) {
157 resource_t *child = (resource_t *) gIter->data;
158
159 clear_bit(child->flags, pe_rsc_managed);
160 set_bit(child->flags, pe_rsc_block);
161 }
162 }
163 break;
164 }
165 crm_debug("%s is active on multiple nodes including %s: %s",
166 rsc->id, node->details->uname,
167 recovery2text(rsc->recovery_type));
168
169 } else {
170 pe_rsc_trace(rsc, "Resource %s is active on: %s", rsc->id, node->details->uname);
171 }
172
173 if (rsc->parent != NULL) {
174 native_add_running(rsc->parent, node, data_set);
175 }
176 }
177
178 static void
recursive_clear_unique(pe_resource_t * rsc)179 recursive_clear_unique(pe_resource_t *rsc)
180 {
181 clear_bit(rsc->flags, pe_rsc_unique);
182 add_hash_param(rsc->meta, XML_RSC_ATTR_UNIQUE, XML_BOOLEAN_FALSE);
183
184 for (GList *child = rsc->children; child != NULL; child = child->next) {
185 recursive_clear_unique((pe_resource_t *) child->data);
186 }
187 }
188
189 gboolean
native_unpack(resource_t * rsc,pe_working_set_t * data_set)190 native_unpack(resource_t * rsc, pe_working_set_t * data_set)
191 {
192 resource_t *parent = uber_parent(rsc);
193 native_variant_data_t *native_data = NULL;
194 const char *standard = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
195 uint32_t ra_caps = pcmk_get_ra_caps(standard);
196
197 pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
198
199 native_data = calloc(1, sizeof(native_variant_data_t));
200 rsc->variant_opaque = native_data;
201
202 // Only some agent standards support unique and promotable clones
203 if (is_not_set(ra_caps, pcmk_ra_cap_unique)
204 && is_set(rsc->flags, pe_rsc_unique) && pe_rsc_is_clone(parent)) {
205
206 /* @COMPAT We should probably reject this situation as an error (as we
207 * do for promotable below) rather than warn and convert, but that would
208 * be a backward-incompatible change that we should probably do with a
209 * transform at a schema major version bump.
210 */
211 pe__force_anon(standard, parent, rsc->id, data_set);
212
213 /* Clear globally-unique on the parent and all its descendents unpacked
214 * so far (clearing the parent should make any future children unpacking
215 * correct). We have to clear this resource explicitly because it isn't
216 * hooked into the parent's children yet.
217 */
218 recursive_clear_unique(parent);
219 recursive_clear_unique(rsc);
220 }
221 if (is_not_set(ra_caps, pcmk_ra_cap_promotable)) {
222 const char *stateful = g_hash_table_lookup(parent->meta, "stateful");
223
224 if (safe_str_eq(stateful, XML_BOOLEAN_TRUE)) {
225 pe_err
226 ("Resource %s is of type %s and therefore cannot be used as a master/slave resource",
227 rsc->id, standard);
228 return FALSE;
229 }
230 }
231 return TRUE;
232 }
233
234 static bool
rsc_is_on_node(resource_t * rsc,node_t * node,int flags)235 rsc_is_on_node(resource_t *rsc, node_t *node, int flags)
236 {
237 pe_rsc_trace(rsc, "Checking whether %s is on %s",
238 rsc->id, node->details->uname);
239
240 if (is_set(flags, pe_find_current) && rsc->running_on) {
241
242 for (GListPtr iter = rsc->running_on; iter; iter = iter->next) {
243 node_t *loc = (node_t *) iter->data;
244
245 if (loc->details == node->details) {
246 return TRUE;
247 }
248 }
249
250 } else if (is_set(flags, pe_find_inactive) && (rsc->running_on == NULL)) {
251 return TRUE;
252
253 } else if (is_not_set(flags, pe_find_current) && rsc->allocated_to
254 && (rsc->allocated_to->details == node->details)) {
255 return TRUE;
256 }
257 return FALSE;
258 }
259
260 resource_t *
native_find_rsc(resource_t * rsc,const char * id,node_t * on_node,int flags)261 native_find_rsc(resource_t * rsc, const char *id, node_t * on_node, int flags)
262 {
263 bool match = FALSE;
264 resource_t *result = NULL;
265
266 CRM_CHECK(id && rsc && rsc->id, return NULL);
267
268 if (flags & pe_find_clone) {
269 const char *rid = ID(rsc->xml);
270
271 if (!pe_rsc_is_clone(uber_parent(rsc))) {
272 match = FALSE;
273
274 } else if (!strcmp(id, rsc->id) || safe_str_eq(id, rid)) {
275 match = TRUE;
276 }
277
278 } else if (!strcmp(id, rsc->id)) {
279 match = TRUE;
280
281 } else if (is_set(flags, pe_find_renamed)
282 && rsc->clone_name && strcmp(rsc->clone_name, id) == 0) {
283 match = TRUE;
284
285 } else if (is_set(flags, pe_find_any)
286 || (is_set(flags, pe_find_anon)
287 && is_not_set(rsc->flags, pe_rsc_unique))) {
288 match = pe_base_name_eq(rsc, id);
289 }
290
291 if (match && on_node) {
292 bool match_node = rsc_is_on_node(rsc, on_node, flags);
293
294 if (match_node == FALSE) {
295 match = FALSE;
296 }
297 }
298
299 if (match) {
300 return rsc;
301 }
302
303 for (GListPtr gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
304 resource_t *child = (resource_t *) gIter->data;
305
306 result = rsc->fns->find_rsc(child, id, on_node, flags);
307 if (result) {
308 return result;
309 }
310 }
311 return NULL;
312 }
313
314 char *
native_parameter(resource_t * rsc,node_t * node,gboolean create,const char * name,pe_working_set_t * data_set)315 native_parameter(resource_t * rsc, node_t * node, gboolean create, const char *name,
316 pe_working_set_t * data_set)
317 {
318 char *value_copy = NULL;
319 const char *value = NULL;
320 GHashTable *hash = NULL;
321 GHashTable *local_hash = NULL;
322
323 CRM_CHECK(rsc != NULL, return NULL);
324 CRM_CHECK(name != NULL && strlen(name) != 0, return NULL);
325
326 pe_rsc_trace(rsc, "Looking up %s in %s", name, rsc->id);
327
328 if (create || g_hash_table_size(rsc->parameters) == 0) {
329 if (node != NULL) {
330 pe_rsc_trace(rsc, "Creating hash with node %s", node->details->uname);
331 } else {
332 pe_rsc_trace(rsc, "Creating default hash");
333 }
334
335 local_hash = crm_str_table_new();
336
337 get_rsc_attributes(local_hash, rsc, node, data_set);
338
339 hash = local_hash;
340 } else {
341 hash = rsc->parameters;
342 }
343
344 value = g_hash_table_lookup(hash, name);
345 if (value == NULL) {
346 /* try meta attributes instead */
347 value = g_hash_table_lookup(rsc->meta, name);
348 }
349
350 if (value != NULL) {
351 value_copy = strdup(value);
352 }
353 if (local_hash != NULL) {
354 g_hash_table_destroy(local_hash);
355 }
356 return value_copy;
357 }
358
359 gboolean
native_active(resource_t * rsc,gboolean all)360 native_active(resource_t * rsc, gboolean all)
361 {
362 GListPtr gIter = rsc->running_on;
363
364 for (; gIter != NULL; gIter = gIter->next) {
365 node_t *a_node = (node_t *) gIter->data;
366
367 if (a_node->details->unclean) {
368 crm_debug("Resource %s: node %s is unclean", rsc->id, a_node->details->uname);
369 return TRUE;
370 } else if (a_node->details->online == FALSE) {
371 crm_debug("Resource %s: node %s is offline", rsc->id, a_node->details->uname);
372 } else {
373 crm_debug("Resource %s active on %s", rsc->id, a_node->details->uname);
374 return TRUE;
375 }
376 }
377
378 return FALSE;
379 }
380
381 struct print_data_s {
382 long options;
383 void *print_data;
384 };
385
386 static void
native_print_attr(gpointer key,gpointer value,gpointer user_data)387 native_print_attr(gpointer key, gpointer value, gpointer user_data)
388 {
389 long options = ((struct print_data_s *)user_data)->options;
390 void *print_data = ((struct print_data_s *)user_data)->print_data;
391
392 status_print("Option: %s = %s\n", (char *)key, (char *)value);
393 }
394
395 static const char *
native_pending_state(resource_t * rsc)396 native_pending_state(resource_t * rsc)
397 {
398 const char *pending_state = NULL;
399
400 if (safe_str_eq(rsc->pending_task, CRMD_ACTION_START)) {
401 pending_state = "Starting";
402
403 } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_STOP)) {
404 pending_state = "Stopping";
405
406 } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_MIGRATE)) {
407 pending_state = "Migrating";
408
409 } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_MIGRATED)) {
410 /* Work might be done in here. */
411 pending_state = "Migrating";
412
413 } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_PROMOTE)) {
414 pending_state = "Promoting";
415
416 } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_DEMOTE)) {
417 pending_state = "Demoting";
418 }
419
420 return pending_state;
421 }
422
423 static const char *
native_pending_task(resource_t * rsc)424 native_pending_task(resource_t * rsc)
425 {
426 const char *pending_task = NULL;
427
428 if (safe_str_eq(rsc->pending_task, CRMD_ACTION_NOTIFY)) {
429 /* "Notifying" is not very useful to be shown. */
430 pending_task = NULL;
431
432 } else if (safe_str_eq(rsc->pending_task, CRMD_ACTION_STATUS)) {
433 pending_task = "Monitoring";
434
435 /* Pending probes are not printed, even if pending
436 * operations are requested. If someone ever requests that
437 * behavior, uncomment this and the corresponding part of
438 * unpack.c:unpack_rsc_op().
439 */
440 /*
441 } else if (safe_str_eq(rsc->pending_task, "probe")) {
442 pending_task = "Checking";
443 */
444 }
445
446 return pending_task;
447 }
448
449 static enum rsc_role_e
native_displayable_role(resource_t * rsc)450 native_displayable_role(resource_t *rsc)
451 {
452 enum rsc_role_e role = rsc->role;
453
454 if ((role == RSC_ROLE_STARTED)
455 && (uber_parent(rsc)->variant == pe_master)) {
456
457 role = RSC_ROLE_SLAVE;
458 }
459 return role;
460 }
461
462 static const char *
native_displayable_state(resource_t * rsc,long options)463 native_displayable_state(resource_t *rsc, long options)
464 {
465 const char *rsc_state = NULL;
466
467 if (options & pe_print_pending) {
468 rsc_state = native_pending_state(rsc);
469 }
470 if (rsc_state == NULL) {
471 rsc_state = role2text(native_displayable_role(rsc));
472 }
473 return rsc_state;
474 }
475
476 static void
native_print_xml(resource_t * rsc,const char * pre_text,long options,void * print_data)477 native_print_xml(resource_t * rsc, const char *pre_text, long options, void *print_data)
478 {
479 const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
480 const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
481 const char *rsc_state = native_displayable_state(rsc, options);
482 const char *target_role = NULL;
483
484 /* resource information. */
485 status_print("%s<resource ", pre_text);
486 status_print("id=\"%s\" ", rsc_printable_id(rsc));
487 status_print("resource_agent=\"%s%s%s:%s\" ",
488 class,
489 prov ? "::" : "", prov ? prov : "", crm_element_value(rsc->xml, XML_ATTR_TYPE));
490
491 status_print("role=\"%s\" ", rsc_state);
492 if (rsc->meta) {
493 target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
494 }
495 if (target_role) {
496 status_print("target_role=\"%s\" ", target_role);
497 }
498 status_print("active=\"%s\" ", rsc->fns->active(rsc, TRUE) ? "true" : "false");
499 status_print("orphaned=\"%s\" ", is_set(rsc->flags, pe_rsc_orphan) ? "true" : "false");
500 status_print("blocked=\"%s\" ", is_set(rsc->flags, pe_rsc_block) ? "true" : "false");
501 status_print("managed=\"%s\" ", is_set(rsc->flags, pe_rsc_managed) ? "true" : "false");
502 status_print("failed=\"%s\" ", is_set(rsc->flags, pe_rsc_failed) ? "true" : "false");
503 status_print("failure_ignored=\"%s\" ",
504 is_set(rsc->flags, pe_rsc_failure_ignored) ? "true" : "false");
505 status_print("nodes_running_on=\"%d\" ", g_list_length(rsc->running_on));
506
507 if (options & pe_print_pending) {
508 const char *pending_task = native_pending_task(rsc);
509
510 if (pending_task) {
511 status_print("pending=\"%s\" ", pending_task);
512 }
513 }
514
515 if (options & pe_print_dev) {
516 status_print("provisional=\"%s\" ",
517 is_set(rsc->flags, pe_rsc_provisional) ? "true" : "false");
518 status_print("runnable=\"%s\" ", is_set(rsc->flags, pe_rsc_runnable) ? "true" : "false");
519 status_print("priority=\"%f\" ", (double)rsc->priority);
520 status_print("variant=\"%s\" ", crm_element_name(rsc->xml));
521 }
522
523 /* print out the nodes this resource is running on */
524 if (options & pe_print_rsconly) {
525 status_print("/>\n");
526 /* do nothing */
527 } else if (rsc->running_on != NULL) {
528 GListPtr gIter = rsc->running_on;
529
530 status_print(">\n");
531 for (; gIter != NULL; gIter = gIter->next) {
532 node_t *node = (node_t *) gIter->data;
533
534 status_print("%s <node name=\"%s\" id=\"%s\" cached=\"%s\"/>\n", pre_text,
535 node->details->uname, node->details->id,
536 node->details->online ? "false" : "true");
537 }
538 status_print("%s</resource>\n", pre_text);
539 } else {
540 status_print("/>\n");
541 }
542 }
543
544 /* making this inline rather than a macro prevents a coverity "unreachable"
545 * warning on the first usage
546 */
547 static inline const char *
comma_if(int i)548 comma_if(int i)
549 {
550 return i? ", " : "";
551 }
552
553 void
common_print(resource_t * rsc,const char * pre_text,const char * name,node_t * node,long options,void * print_data)554 common_print(resource_t * rsc, const char *pre_text, const char *name, node_t *node, long options, void *print_data)
555 {
556 const char *desc = NULL;
557 const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
558 const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
559 const char *target_role = NULL;
560 enum rsc_role_e role = native_displayable_role(rsc);
561
562 int offset = 0;
563 int flagOffset = 0;
564 char buffer[LINE_MAX];
565 char flagBuffer[LINE_MAX];
566
567 CRM_ASSERT(rsc->variant == pe_native);
568 CRM_ASSERT(kind != NULL);
569
570 if (rsc->meta) {
571 const char *is_internal = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_INTERNAL_RSC);
572 if (crm_is_true(is_internal) && is_not_set(options, pe_print_implicit)) {
573 crm_trace("skipping print of internal resource %s", rsc->id);
574 return;
575 }
576 target_role = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
577 }
578
579 if (pre_text == NULL && (options & pe_print_printf)) {
580 pre_text = " ";
581 }
582
583 if (options & pe_print_xml) {
584 native_print_xml(rsc, pre_text, options, print_data);
585 return;
586 }
587
588 if ((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) {
589 node = NULL;
590 }
591
592 if (options & pe_print_html) {
593 if (is_not_set(rsc->flags, pe_rsc_managed)) {
594 status_print("<font color=\"yellow\">");
595
596 } else if (is_set(rsc->flags, pe_rsc_failed)) {
597 status_print("<font color=\"red\">");
598
599 } else if (rsc->variant == pe_native && (rsc->running_on == NULL)) {
600 status_print("<font color=\"red\">");
601
602 } else if (g_list_length(rsc->running_on) > 1) {
603 status_print("<font color=\"orange\">");
604
605 } else if (is_set(rsc->flags, pe_rsc_failure_ignored)) {
606 status_print("<font color=\"yellow\">");
607
608 } else {
609 status_print("<font color=\"green\">");
610 }
611 }
612
613 if(pre_text) {
614 offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", pre_text);
615 }
616 offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", name);
617 offset += snprintf(buffer + offset, LINE_MAX - offset, "\t(%s", class);
618 if (is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
619 const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
620 offset += snprintf(buffer + offset, LINE_MAX - offset, "::%s", prov);
621 }
622 offset += snprintf(buffer + offset, LINE_MAX - offset, ":%s):\t", kind);
623 if(is_set(rsc->flags, pe_rsc_orphan)) {
624 offset += snprintf(buffer + offset, LINE_MAX - offset, " ORPHANED ");
625 }
626 if(role > RSC_ROLE_SLAVE && is_set(rsc->flags, pe_rsc_failed)) {
627 offset += snprintf(buffer + offset, LINE_MAX - offset, "FAILED %s", role2text(role));
628 } else if(is_set(rsc->flags, pe_rsc_failed)) {
629 offset += snprintf(buffer + offset, LINE_MAX - offset, "FAILED");
630 } else {
631 const char *rsc_state = native_displayable_state(rsc, options);
632
633 offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", rsc_state);
634 }
635
636 if(node) {
637 offset += snprintf(buffer + offset, LINE_MAX - offset, " %s", node->details->uname);
638
639 if (node->details->online == FALSE && node->details->unclean) {
640 flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
641 "%sUNCLEAN", comma_if(flagOffset));
642 }
643 }
644
645 if (options & pe_print_pending) {
646 const char *pending_task = native_pending_task(rsc);
647
648 if (pending_task) {
649 flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
650 "%s%s", comma_if(flagOffset), pending_task);
651 }
652 }
653
654 if (target_role) {
655 enum rsc_role_e target_role_e = text2role(target_role);
656
657 /* Ignore target role Started, as it is the default anyways
658 * (and would also allow a Master to be Master).
659 * Show if target role limits our abilities. */
660 if (target_role_e == RSC_ROLE_STOPPED) {
661 flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
662 "%sdisabled", comma_if(flagOffset));
663
664 } else if (uber_parent(rsc)->variant == pe_master
665 && target_role_e == RSC_ROLE_SLAVE) {
666 flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
667 "%starget-role:%s", comma_if(flagOffset), target_role);
668 }
669 }
670
671 if (is_set(rsc->flags, pe_rsc_block)) {
672 flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
673 "%sblocked", comma_if(flagOffset));
674
675 } else if (is_not_set(rsc->flags, pe_rsc_managed)) {
676 flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
677 "%sunmanaged", comma_if(flagOffset));
678 }
679
680 if(is_set(rsc->flags, pe_rsc_failure_ignored)) {
681 flagOffset += snprintf(flagBuffer + flagOffset, LINE_MAX - flagOffset,
682 "%sfailure ignored", comma_if(flagOffset));
683 }
684
685 if ((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) {
686 desc = crm_element_value(rsc->xml, XML_ATTR_DESC);
687 }
688
689 CRM_LOG_ASSERT(offset > 0);
690 if(flagOffset > 0) {
691 status_print("%s (%s)%s%s", buffer, flagBuffer, desc?" ":"", desc?desc:"");
692 } else {
693 status_print("%s%s%s", buffer, desc?" ":"", desc?desc:"");
694 }
695
696 #if CURSES_ENABLED
697 if ((options & pe_print_rsconly) || g_list_length(rsc->running_on) > 1) {
698 /* Done */
699
700 } else if (options & pe_print_ncurses) {
701 /* coverity[negative_returns] False positive */
702 move(-1, 0);
703 }
704 #endif
705
706 if (options & pe_print_html) {
707 status_print(" </font> ");
708 }
709
710 if ((options & pe_print_rsconly)) {
711
712 } else if (g_list_length(rsc->running_on) > 1) {
713 GListPtr gIter = rsc->running_on;
714 int counter = 0;
715
716 if (options & pe_print_html) {
717 status_print("<ul>\n");
718 } else if ((options & pe_print_printf)
719 || (options & pe_print_ncurses)) {
720 status_print("[");
721 }
722
723 for (; gIter != NULL; gIter = gIter->next) {
724 node_t *n = (node_t *) gIter->data;
725
726 counter++;
727
728 if (options & pe_print_html) {
729 status_print("<li>\n%s", n->details->uname);
730
731 } else if ((options & pe_print_printf)
732 || (options & pe_print_ncurses)) {
733 status_print(" %s", n->details->uname);
734
735 } else if ((options & pe_print_log)) {
736 status_print("\t%d : %s", counter, n->details->uname);
737
738 } else {
739 status_print("%s", n->details->uname);
740 }
741 if (options & pe_print_html) {
742 status_print("</li>\n");
743
744 }
745 }
746
747 if (options & pe_print_html) {
748 status_print("</ul>\n");
749 } else if ((options & pe_print_printf)
750 || (options & pe_print_ncurses)) {
751 status_print(" ]");
752 }
753 }
754
755 if (options & pe_print_html) {
756 status_print("<br/>\n");
757 } else if (options & pe_print_suppres_nl) {
758 /* nothing */
759 } else if ((options & pe_print_printf) || (options & pe_print_ncurses)) {
760 status_print("\n");
761 }
762
763 if (options & pe_print_details) {
764 struct print_data_s pdata;
765
766 pdata.options = options;
767 pdata.print_data = print_data;
768 g_hash_table_foreach(rsc->parameters, native_print_attr, &pdata);
769 }
770
771 if (options & pe_print_dev) {
772 GHashTableIter iter;
773 node_t *n = NULL;
774
775 status_print("%s\t(%s%svariant=%s, priority=%f)", pre_text,
776 is_set(rsc->flags, pe_rsc_provisional) ? "provisional, " : "",
777 is_set(rsc->flags, pe_rsc_runnable) ? "" : "non-startable, ",
778 crm_element_name(rsc->xml), (double)rsc->priority);
779 status_print("%s\tAllowed Nodes", pre_text);
780 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
781 while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
782 status_print("%s\t * %s %d", pre_text, n->details->uname, n->weight);
783 }
784 }
785
786 if (options & pe_print_max_details) {
787 GHashTableIter iter;
788 node_t *n = NULL;
789
790 status_print("%s\t=== Allowed Nodes\n", pre_text);
791 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
792 while (g_hash_table_iter_next(&iter, NULL, (void **)&n)) {
793 print_node("\t", n, FALSE);
794 }
795 }
796 }
797
798 void
native_print(resource_t * rsc,const char * pre_text,long options,void * print_data)799 native_print(resource_t * rsc, const char *pre_text, long options, void *print_data)
800 {
801 node_t *node = NULL;
802
803 CRM_ASSERT(rsc->variant == pe_native);
804 if (options & pe_print_xml) {
805 native_print_xml(rsc, pre_text, options, print_data);
806 return;
807 }
808
809 node = pe__current_node(rsc);
810
811 if (node == NULL) {
812 // This is set only if a non-probe action is pending on this node
813 node = rsc->pending_node;
814 }
815
816 common_print(rsc, pre_text, rsc_printable_id(rsc), node, options, print_data);
817 }
818
819 void
native_free(resource_t * rsc)820 native_free(resource_t * rsc)
821 {
822 pe_rsc_trace(rsc, "Freeing resource action list (not the data)");
823 common_free(rsc);
824 }
825
826 enum rsc_role_e
native_resource_state(const resource_t * rsc,gboolean current)827 native_resource_state(const resource_t * rsc, gboolean current)
828 {
829 enum rsc_role_e role = rsc->next_role;
830
831 if (current) {
832 role = rsc->role;
833 }
834 pe_rsc_trace(rsc, "%s state: %s", rsc->id, role2text(role));
835 return role;
836 }
837
838 /*!
839 * \internal
840 * \brief List nodes where a resource (or any of its children) is
841 *
842 * \param[in] rsc Resource to check
843 * \param[out] list List to add result to
844 * \param[in] current 0 = where known, 1 = running, 2 = running or pending
845 *
846 * \return If list contains only one node, that node
847 */
848 pe_node_t *
native_location(const pe_resource_t * rsc,GList ** list,int current)849 native_location(const pe_resource_t *rsc, GList **list, int current)
850 {
851 node_t *one = NULL;
852 GListPtr result = NULL;
853
854 if (rsc->children) {
855 GListPtr gIter = rsc->children;
856
857 for (; gIter != NULL; gIter = gIter->next) {
858 resource_t *child = (resource_t *) gIter->data;
859
860 child->fns->location(child, &result, current);
861 }
862
863 } else if (current) {
864
865 if (rsc->running_on) {
866 result = g_list_copy(rsc->running_on);
867 }
868 if ((current == 2) && rsc->pending_node
869 && !pe_find_node_id(result, rsc->pending_node->details->id)) {
870 result = g_list_append(result, rsc->pending_node);
871 }
872
873 } else if (current == FALSE && rsc->allocated_to) {
874 result = g_list_append(NULL, rsc->allocated_to);
875 }
876
877 if (result && (result->next == NULL)) {
878 one = result->data;
879 }
880
881 if (list) {
882 GListPtr gIter = result;
883
884 for (; gIter != NULL; gIter = gIter->next) {
885 node_t *node = (node_t *) gIter->data;
886
887 if (*list == NULL || pe_find_node_id(*list, node->details->id) == NULL) {
888 *list = g_list_append(*list, node);
889 }
890 }
891 }
892
893 g_list_free(result);
894 return one;
895 }
896
897 static void
get_rscs_brief(GListPtr rsc_list,GHashTable * rsc_table,GHashTable * active_table)898 get_rscs_brief(GListPtr rsc_list, GHashTable * rsc_table, GHashTable * active_table)
899 {
900 GListPtr gIter = rsc_list;
901
902 for (; gIter != NULL; gIter = gIter->next) {
903 resource_t *rsc = (resource_t *) gIter->data;
904
905 const char *class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
906 const char *kind = crm_element_value(rsc->xml, XML_ATTR_TYPE);
907
908 int offset = 0;
909 char buffer[LINE_MAX];
910
911 int *rsc_counter = NULL;
912 int *active_counter = NULL;
913
914 if (rsc->variant != pe_native) {
915 continue;
916 }
917
918 offset += snprintf(buffer + offset, LINE_MAX - offset, "%s", class);
919 if (is_set(pcmk_get_ra_caps(class), pcmk_ra_cap_provider)) {
920 const char *prov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER);
921 offset += snprintf(buffer + offset, LINE_MAX - offset, "::%s", prov);
922 }
923 offset += snprintf(buffer + offset, LINE_MAX - offset, ":%s", kind);
924 CRM_LOG_ASSERT(offset > 0);
925
926 if (rsc_table) {
927 rsc_counter = g_hash_table_lookup(rsc_table, buffer);
928 if (rsc_counter == NULL) {
929 rsc_counter = calloc(1, sizeof(int));
930 *rsc_counter = 0;
931 g_hash_table_insert(rsc_table, strdup(buffer), rsc_counter);
932 }
933 (*rsc_counter)++;
934 }
935
936 if (active_table) {
937 GListPtr gIter2 = rsc->running_on;
938
939 for (; gIter2 != NULL; gIter2 = gIter2->next) {
940 node_t *node = (node_t *) gIter2->data;
941 GHashTable *node_table = NULL;
942
943 if (node->details->unclean == FALSE && node->details->online == FALSE) {
944 continue;
945 }
946
947 node_table = g_hash_table_lookup(active_table, node->details->uname);
948 if (node_table == NULL) {
949 node_table = crm_str_table_new();
950 g_hash_table_insert(active_table, strdup(node->details->uname), node_table);
951 }
952
953 active_counter = g_hash_table_lookup(node_table, buffer);
954 if (active_counter == NULL) {
955 active_counter = calloc(1, sizeof(int));
956 *active_counter = 0;
957 g_hash_table_insert(node_table, strdup(buffer), active_counter);
958 }
959 (*active_counter)++;
960 }
961 }
962 }
963 }
964
965 static void
destroy_node_table(gpointer data)966 destroy_node_table(gpointer data)
967 {
968 GHashTable *node_table = data;
969
970 if (node_table) {
971 g_hash_table_destroy(node_table);
972 }
973 }
974
975 void
print_rscs_brief(GListPtr rsc_list,const char * pre_text,long options,void * print_data,gboolean print_all)976 print_rscs_brief(GListPtr rsc_list, const char *pre_text, long options,
977 void *print_data, gboolean print_all)
978 {
979 GHashTable *rsc_table = crm_str_table_new();
980 GHashTable *active_table = g_hash_table_new_full(crm_str_hash, g_str_equal,
981 free, destroy_node_table);
982 GHashTableIter hash_iter;
983 char *type = NULL;
984 int *rsc_counter = NULL;
985
986 get_rscs_brief(rsc_list, rsc_table, active_table);
987
988 g_hash_table_iter_init(&hash_iter, rsc_table);
989 while (g_hash_table_iter_next(&hash_iter, (gpointer *)&type, (gpointer *)&rsc_counter)) {
990 GHashTableIter hash_iter2;
991 char *node_name = NULL;
992 GHashTable *node_table = NULL;
993 int active_counter_all = 0;
994
995 g_hash_table_iter_init(&hash_iter2, active_table);
996 while (g_hash_table_iter_next(&hash_iter2, (gpointer *)&node_name, (gpointer *)&node_table)) {
997 int *active_counter = g_hash_table_lookup(node_table, type);
998
999 if (active_counter == NULL || *active_counter == 0) {
1000 continue;
1001
1002 } else {
1003 active_counter_all += *active_counter;
1004 }
1005
1006 if (options & pe_print_rsconly) {
1007 node_name = NULL;
1008 }
1009
1010 if (options & pe_print_html) {
1011 status_print("<li>\n");
1012 }
1013
1014 if (print_all) {
1015 status_print("%s%d/%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
1016 active_counter ? *active_counter : 0,
1017 rsc_counter ? *rsc_counter : 0, type,
1018 active_counter && (*active_counter > 0) && node_name ? node_name : "");
1019 } else {
1020 status_print("%s%d\t(%s):\tActive %s\n", pre_text ? pre_text : "",
1021 active_counter ? *active_counter : 0, type,
1022 active_counter && (*active_counter > 0) && node_name ? node_name : "");
1023 }
1024
1025 if (options & pe_print_html) {
1026 status_print("</li>\n");
1027 }
1028 }
1029
1030 if (print_all && active_counter_all == 0) {
1031 if (options & pe_print_html) {
1032 status_print("<li>\n");
1033 }
1034
1035 status_print("%s%d/%d\t(%s):\tActive\n", pre_text ? pre_text : "",
1036 active_counter_all,
1037 rsc_counter ? *rsc_counter : 0, type);
1038
1039 if (options & pe_print_html) {
1040 status_print("</li>\n");
1041 }
1042 }
1043 }
1044
1045 if (rsc_table) {
1046 g_hash_table_destroy(rsc_table);
1047 rsc_table = NULL;
1048 }
1049 if (active_table) {
1050 g_hash_table_destroy(active_table);
1051 active_table = NULL;
1052 }
1053 }
1054