This source file includes following definitions.
- pe__bundle_max
- pe__bundled_resource
- pe__get_rsc_in_container
- pe__node_is_bundle_instance
- pe__first_container
- pe__foreach_bundle_replica
- pe__foreach_const_bundle_replica
- next_ip
- allocate_ip
- create_resource
- valid_network
- create_ip_resource
- container_agent_str
- create_container_resource
- disallow_node
- create_remote_resource
- create_replica_resources
- mount_add
- mount_free
- port_free
- replica_for_remote
- pe__bundle_needs_remote_name
- pe__add_bundle_remote_name
- pe__unpack_bundle
- replica_resource_active
- pe__bundle_active
- pe__find_bundle_replica
- print_rsc_in_list
- bundle_print_xml
- PCMK__OUTPUT_ARGS
- pe__bundle_replica_output_html
- get_unmanaged_str
- PCMK__OUTPUT_ARGS
- pe__bundle_replica_output_text
- PCMK__OUTPUT_ARGS
- print_bundle_replica
- pe__print_bundle
- free_bundle_replica
- pe__free_bundle
- pe__bundle_resource_state
- pe_bundle_replicas
- pe__count_bundle
- pe__bundle_is_filtered
- pe__bundle_containers
- pe__bundle_active_node
- pe__bundle_max_per_node
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <ctype.h>
13 #include <stdint.h>
14
15 #include <crm/pengine/rules.h>
16 #include <crm/pengine/status.h>
17 #include <crm/pengine/internal.h>
18 #include <crm/common/xml.h>
19 #include <crm/common/output.h>
20 #include <crm/common/xml_internal.h>
21 #include <pe_status_private.h>
22
23 enum pe__bundle_mount_flags {
24 pe__bundle_mount_none = 0x00,
25
26
27 pe__bundle_mount_subdir = 0x01
28 };
29
30 typedef struct {
31 char *source;
32 char *target;
33 char *options;
34 uint32_t flags;
35 } pe__bundle_mount_t;
36
37 typedef struct {
38 char *source;
39 char *target;
40 } pe__bundle_port_t;
41
42 enum pe__container_agent {
43 PE__CONTAINER_AGENT_UNKNOWN,
44 PE__CONTAINER_AGENT_DOCKER,
45 PE__CONTAINER_AGENT_RKT,
46 PE__CONTAINER_AGENT_PODMAN,
47 };
48
49 #define PE__CONTAINER_AGENT_UNKNOWN_S "unknown"
50 #define PE__CONTAINER_AGENT_DOCKER_S "docker"
51 #define PE__CONTAINER_AGENT_RKT_S "rkt"
52 #define PE__CONTAINER_AGENT_PODMAN_S "podman"
53
54 typedef struct pe__bundle_variant_data_s {
55 int promoted_max;
56 int nreplicas;
57 int nreplicas_per_host;
58 char *prefix;
59 char *image;
60 const char *ip_last;
61 char *host_network;
62 char *host_netmask;
63 char *control_port;
64 char *container_network;
65 char *ip_range_start;
66 gboolean add_host;
67 gchar *container_host_options;
68 char *container_command;
69 char *launcher_options;
70 const char *attribute_target;
71
72 pcmk_resource_t *child;
73
74 GList *replicas;
75 GList *ports;
76 GList *mounts;
77
78 enum pe__container_agent agent_type;
79 } pe__bundle_variant_data_t;
80
81 #define get_bundle_variant_data(data, rsc) \
82 pcmk__assert(pcmk__is_bundle(rsc) && (rsc->variant_opaque != NULL)); \
83 data = (pe__bundle_variant_data_t *) rsc->variant_opaque;
84
85
86
87
88
89
90
91
92
93 int
94 pe__bundle_max(const pcmk_resource_t *rsc)
95 {
96 const pe__bundle_variant_data_t *bundle_data = NULL;
97
98 get_bundle_variant_data(bundle_data, pe__const_top_resource(rsc, true));
99 return bundle_data->nreplicas;
100 }
101
102
103
104
105
106
107
108
109
110 pcmk_resource_t *
111 pe__bundled_resource(const pcmk_resource_t *rsc)
112 {
113 const pe__bundle_variant_data_t *bundle_data = NULL;
114
115 get_bundle_variant_data(bundle_data, pe__const_top_resource(rsc, true));
116 return bundle_data->child;
117 }
118
119
120
121
122
123
124
125
126
127
128 const pcmk_resource_t *
129 pe__get_rsc_in_container(const pcmk_resource_t *instance)
130 {
131 const pe__bundle_variant_data_t *data = NULL;
132 const pcmk_resource_t *top = pe__const_top_resource(instance, true);
133
134 if (!pcmk__is_bundle(top)) {
135 return NULL;
136 }
137 get_bundle_variant_data(data, top);
138
139 for (const GList *iter = data->replicas; iter != NULL; iter = iter->next) {
140 const pcmk__bundle_replica_t *replica = iter->data;
141
142 if (instance == replica->container) {
143 return replica->child;
144 }
145 }
146 return NULL;
147 }
148
149
150
151
152
153
154
155
156
157
158 bool
159 pe__node_is_bundle_instance(const pcmk_resource_t *bundle,
160 const pcmk_node_t *node)
161 {
162 pe__bundle_variant_data_t *bundle_data = NULL;
163
164 get_bundle_variant_data(bundle_data, bundle);
165 for (GList *iter = bundle_data->replicas; iter != NULL; iter = iter->next) {
166 pcmk__bundle_replica_t *replica = iter->data;
167
168 if (pcmk__same_node(node, replica->node)) {
169 return true;
170 }
171 }
172 return false;
173 }
174
175
176
177
178
179
180
181
182
183
184 pcmk_resource_t *
185 pe__first_container(const pcmk_resource_t *bundle)
186 {
187 const pe__bundle_variant_data_t *bundle_data = NULL;
188 const pcmk__bundle_replica_t *replica = NULL;
189
190 get_bundle_variant_data(bundle_data, bundle);
191 if (bundle_data->replicas == NULL) {
192 return NULL;
193 }
194 replica = bundle_data->replicas->data;
195 return replica->container;
196 }
197
198
199
200
201
202
203
204
205
206
207 void
208 pe__foreach_bundle_replica(pcmk_resource_t *bundle,
209 bool (*fn)(pcmk__bundle_replica_t *, void *),
210 void *user_data)
211 {
212 const pe__bundle_variant_data_t *bundle_data = NULL;
213
214 get_bundle_variant_data(bundle_data, bundle);
215 for (GList *iter = bundle_data->replicas; iter != NULL; iter = iter->next) {
216 if (!fn((pcmk__bundle_replica_t *) iter->data, user_data)) {
217 break;
218 }
219 }
220 }
221
222
223
224
225
226
227
228
229
230
231 void
232 pe__foreach_const_bundle_replica(const pcmk_resource_t *bundle,
233 bool (*fn)(const pcmk__bundle_replica_t *,
234 void *),
235 void *user_data)
236 {
237 const pe__bundle_variant_data_t *bundle_data = NULL;
238
239 get_bundle_variant_data(bundle_data, bundle);
240 for (const GList *iter = bundle_data->replicas; iter != NULL;
241 iter = iter->next) {
242
243 if (!fn((const pcmk__bundle_replica_t *) iter->data, user_data)) {
244 break;
245 }
246 }
247 }
248
249 static char *
250 next_ip(const char *last_ip)
251 {
252 unsigned int oct1 = 0;
253 unsigned int oct2 = 0;
254 unsigned int oct3 = 0;
255 unsigned int oct4 = 0;
256 int rc = sscanf(last_ip, "%u.%u.%u.%u", &oct1, &oct2, &oct3, &oct4);
257
258 if (rc != 4) {
259
260 return NULL;
261
262 } else if (oct3 > 253) {
263 return NULL;
264
265 } else if (oct4 > 253) {
266 ++oct3;
267 oct4 = 1;
268
269 } else {
270 ++oct4;
271 }
272
273 return crm_strdup_printf("%u.%u.%u.%u", oct1, oct2, oct3, oct4);
274 }
275
276 static void
277 allocate_ip(pe__bundle_variant_data_t *data, pcmk__bundle_replica_t *replica,
278 GString *buffer)
279 {
280 if(data->ip_range_start == NULL) {
281 return;
282
283 } else if(data->ip_last) {
284 replica->ipaddr = next_ip(data->ip_last);
285
286 } else {
287 replica->ipaddr = strdup(data->ip_range_start);
288 }
289
290 data->ip_last = replica->ipaddr;
291 switch (data->agent_type) {
292 case PE__CONTAINER_AGENT_DOCKER:
293 case PE__CONTAINER_AGENT_PODMAN:
294 if (data->add_host) {
295 g_string_append_printf(buffer, " --add-host=%s-%d:%s",
296 data->prefix, replica->offset,
297 replica->ipaddr);
298 } else {
299 g_string_append_printf(buffer, " --hosts-entry=%s=%s-%d",
300 replica->ipaddr, data->prefix,
301 replica->offset);
302 }
303 break;
304
305 case PE__CONTAINER_AGENT_RKT:
306 g_string_append_printf(buffer, " --hosts-entry=%s=%s-%d",
307 replica->ipaddr, data->prefix,
308 replica->offset);
309 break;
310
311 default:
312 break;
313 }
314 }
315
316 static xmlNode *
317 create_resource(const char *name, const char *provider, const char *kind)
318 {
319 xmlNode *rsc = pcmk__xe_create(NULL, PCMK_XE_PRIMITIVE);
320
321 crm_xml_add(rsc, PCMK_XA_ID, name);
322 crm_xml_add(rsc, PCMK_XA_CLASS, PCMK_RESOURCE_CLASS_OCF);
323 crm_xml_add(rsc, PCMK_XA_PROVIDER, provider);
324 crm_xml_add(rsc, PCMK_XA_TYPE, kind);
325
326 return rsc;
327 }
328
329
330
331
332
333
334
335
336
337
338
339
340
341 static bool
342 valid_network(pe__bundle_variant_data_t *data)
343 {
344 if(data->ip_range_start) {
345 return TRUE;
346 }
347 if(data->control_port) {
348 if(data->nreplicas_per_host > 1) {
349 pcmk__config_err("Specifying the '" PCMK_XA_CONTROL_PORT "' for %s "
350 "requires '" PCMK_XA_REPLICAS_PER_HOST "=1'",
351 data->prefix);
352 data->nreplicas_per_host = 1;
353
354
355 }
356 return TRUE;
357 }
358 return FALSE;
359 }
360
361 static int
362 create_ip_resource(pcmk_resource_t *parent, pe__bundle_variant_data_t *data,
363 pcmk__bundle_replica_t *replica)
364 {
365 if(data->ip_range_start) {
366 char *id = NULL;
367 xmlNode *xml_ip = NULL;
368 xmlNode *xml_obj = NULL;
369
370 id = crm_strdup_printf("%s-ip-%s", data->prefix, replica->ipaddr);
371 crm_xml_sanitize_id(id);
372 xml_ip = create_resource(id, "heartbeat", "IPaddr2");
373 free(id);
374
375 xml_obj = pcmk__xe_create(xml_ip, PCMK_XE_INSTANCE_ATTRIBUTES);
376 crm_xml_set_id(xml_obj, "%s-attributes-%d",
377 data->prefix, replica->offset);
378
379 crm_create_nvpair_xml(xml_obj, NULL, "ip", replica->ipaddr);
380 if(data->host_network) {
381 crm_create_nvpair_xml(xml_obj, NULL, "nic", data->host_network);
382 }
383
384 if(data->host_netmask) {
385 crm_create_nvpair_xml(xml_obj, NULL,
386 "cidr_netmask", data->host_netmask);
387
388 } else {
389 crm_create_nvpair_xml(xml_obj, NULL, "cidr_netmask", "32");
390 }
391
392 xml_obj = pcmk__xe_create(xml_ip, PCMK_XE_OPERATIONS);
393 crm_create_op_xml(xml_obj, pcmk__xe_id(xml_ip), PCMK_ACTION_MONITOR,
394 "60s", NULL);
395
396
397
398 if (pe__unpack_resource(xml_ip, &replica->ip, parent,
399 parent->cluster) != pcmk_rc_ok) {
400 return pcmk_rc_unpack_error;
401 }
402
403 parent->children = g_list_append(parent->children, replica->ip);
404 }
405 return pcmk_rc_ok;
406 }
407
408 static const char*
409 container_agent_str(enum pe__container_agent t)
410 {
411 switch (t) {
412 case PE__CONTAINER_AGENT_DOCKER: return PE__CONTAINER_AGENT_DOCKER_S;
413 case PE__CONTAINER_AGENT_RKT: return PE__CONTAINER_AGENT_RKT_S;
414 case PE__CONTAINER_AGENT_PODMAN: return PE__CONTAINER_AGENT_PODMAN_S;
415 default:
416 break;
417 }
418 return PE__CONTAINER_AGENT_UNKNOWN_S;
419 }
420
421 static int
422 create_container_resource(pcmk_resource_t *parent,
423 const pe__bundle_variant_data_t *data,
424 pcmk__bundle_replica_t *replica)
425 {
426 char *id = NULL;
427 xmlNode *xml_container = NULL;
428 xmlNode *xml_obj = NULL;
429
430
431 const char *hostname_opt = NULL;
432 const char *env_opt = NULL;
433 const char *agent_str = NULL;
434 int volid = 0;
435
436 GString *buffer = NULL;
437 GString *dbuffer = NULL;
438
439
440 switch (data->agent_type) {
441 case PE__CONTAINER_AGENT_DOCKER:
442 case PE__CONTAINER_AGENT_PODMAN:
443 hostname_opt = "-h ";
444 env_opt = "-e ";
445 break;
446 case PE__CONTAINER_AGENT_RKT:
447 hostname_opt = "--hostname=";
448 env_opt = "--environment=";
449 break;
450 default:
451 return pcmk_rc_unpack_error;
452 }
453 agent_str = container_agent_str(data->agent_type);
454
455 buffer = g_string_sized_new(4096);
456
457 id = crm_strdup_printf("%s-%s-%d", data->prefix, agent_str,
458 replica->offset);
459 crm_xml_sanitize_id(id);
460 xml_container = create_resource(id, "heartbeat", agent_str);
461 free(id);
462
463 xml_obj = pcmk__xe_create(xml_container, PCMK_XE_INSTANCE_ATTRIBUTES);
464 crm_xml_set_id(xml_obj, "%s-attributes-%d", data->prefix, replica->offset);
465
466 crm_create_nvpair_xml(xml_obj, NULL, "image", data->image);
467 crm_create_nvpair_xml(xml_obj, NULL, "allow_pull", PCMK_VALUE_TRUE);
468 crm_create_nvpair_xml(xml_obj, NULL, "force_kill", PCMK_VALUE_FALSE);
469 crm_create_nvpair_xml(xml_obj, NULL, "reuse", PCMK_VALUE_FALSE);
470
471 if (data->agent_type == PE__CONTAINER_AGENT_DOCKER) {
472 g_string_append(buffer, " --restart=no");
473 }
474
475
476
477
478
479
480 if (data->ip_range_start != NULL) {
481 g_string_append_printf(buffer, " %s%s-%d", hostname_opt, data->prefix,
482 replica->offset);
483 }
484 pcmk__g_strcat(buffer, " ", env_opt, "PCMK_stderr=1", NULL);
485
486 if (data->container_network != NULL) {
487 pcmk__g_strcat(buffer, " --net=", data->container_network, NULL);
488 }
489
490 if (data->control_port != NULL) {
491 pcmk__g_strcat(buffer, " ", env_opt, "PCMK_" PCMK__ENV_REMOTE_PORT "=",
492 data->control_port, NULL);
493 } else {
494 g_string_append_printf(buffer, " %sPCMK_" PCMK__ENV_REMOTE_PORT "=%d",
495 env_opt, DEFAULT_REMOTE_PORT);
496 }
497
498 for (GList *iter = data->mounts; iter != NULL; iter = iter->next) {
499 pe__bundle_mount_t *mount = (pe__bundle_mount_t *) iter->data;
500 char *source = NULL;
501
502 if (pcmk_is_set(mount->flags, pe__bundle_mount_subdir)) {
503 source = crm_strdup_printf("%s/%s-%d", mount->source, data->prefix,
504 replica->offset);
505 pcmk__add_separated_word(&dbuffer, 1024, source, ",");
506 }
507
508 switch (data->agent_type) {
509 case PE__CONTAINER_AGENT_DOCKER:
510 case PE__CONTAINER_AGENT_PODMAN:
511 pcmk__g_strcat(buffer,
512 " -v ", pcmk__s(source, mount->source),
513 ":", mount->target, NULL);
514
515 if (mount->options != NULL) {
516 pcmk__g_strcat(buffer, ":", mount->options, NULL);
517 }
518 break;
519 case PE__CONTAINER_AGENT_RKT:
520 g_string_append_printf(buffer,
521 " --volume vol%d,kind=host,"
522 "source=%s%s%s "
523 "--mount volume=vol%d,target=%s",
524 volid, pcmk__s(source, mount->source),
525 (mount->options != NULL)? "," : "",
526 pcmk__s(mount->options, ""),
527 volid, mount->target);
528 volid++;
529 break;
530 default:
531 break;
532 }
533 free(source);
534 }
535
536 for (GList *iter = data->ports; iter != NULL; iter = iter->next) {
537 pe__bundle_port_t *port = (pe__bundle_port_t *) iter->data;
538
539 switch (data->agent_type) {
540 case PE__CONTAINER_AGENT_DOCKER:
541 case PE__CONTAINER_AGENT_PODMAN:
542 if (replica->ipaddr != NULL) {
543 pcmk__g_strcat(buffer,
544 " -p ", replica->ipaddr, ":", port->source,
545 ":", port->target, NULL);
546
547 } else if (!pcmk__str_eq(data->container_network,
548 PCMK_VALUE_HOST, pcmk__str_none)) {
549
550 pcmk__g_strcat(buffer,
551 " -p ", port->source, ":", port->target,
552 NULL);
553 }
554 break;
555 case PE__CONTAINER_AGENT_RKT:
556 if (replica->ipaddr != NULL) {
557 pcmk__g_strcat(buffer,
558 " --port=", port->target,
559 ":", replica->ipaddr, ":", port->source,
560 NULL);
561 } else {
562 pcmk__g_strcat(buffer,
563 " --port=", port->target, ":", port->source,
564 NULL);
565 }
566 break;
567 default:
568 break;
569 }
570 }
571
572
573
574
575
576
577
578
579
580
581
582
583
584 if (data->launcher_options != NULL) {
585 pcmk__g_strcat(buffer, " ", data->launcher_options, NULL);
586 }
587
588 if (data->container_host_options != NULL) {
589 pcmk__g_strcat(buffer, " ", data->container_host_options, NULL);
590 }
591
592 crm_create_nvpair_xml(xml_obj, NULL, "run_opts",
593 (const char *) buffer->str);
594 g_string_free(buffer, TRUE);
595
596 crm_create_nvpair_xml(xml_obj, NULL, "mount_points",
597 (dbuffer != NULL)? (const char *) dbuffer->str : "");
598 if (dbuffer != NULL) {
599 g_string_free(dbuffer, TRUE);
600 }
601
602 if (replica->child != NULL) {
603 if (data->container_command != NULL) {
604 crm_create_nvpair_xml(xml_obj, NULL, "run_cmd",
605 data->container_command);
606 } else {
607 crm_create_nvpair_xml(xml_obj, NULL, "run_cmd",
608 SBIN_DIR "/pacemaker-remoted");
609 }
610
611
612
613
614
615
616 crm_create_nvpair_xml(xml_obj, NULL, "monitor_cmd", "/bin/true");
617 #if 0
618
619
620
621
622
623
624 } else if ((child != NULL) && data->untrusted) {
625 crm_create_nvpair_xml(xml_obj, NULL, "run_cmd",
626 CRM_DAEMON_DIR "/pacemaker-execd");
627 crm_create_nvpair_xml(xml_obj, NULL, "monitor_cmd",
628 CRM_DAEMON_DIR "/pacemaker/cts-exec-helper -c poke");
629 #endif
630 } else {
631 if (data->container_command != NULL) {
632 crm_create_nvpair_xml(xml_obj, NULL, "run_cmd",
633 data->container_command);
634 }
635
636
637
638
639
640
641 crm_create_nvpair_xml(xml_obj, NULL, "monitor_cmd", "/bin/true");
642 }
643
644 xml_obj = pcmk__xe_create(xml_container, PCMK_XE_OPERATIONS);
645 crm_create_op_xml(xml_obj, pcmk__xe_id(xml_container), PCMK_ACTION_MONITOR,
646 "60s", NULL);
647
648
649 if (pe__unpack_resource(xml_container, &replica->container, parent,
650 parent->cluster) != pcmk_rc_ok) {
651 return pcmk_rc_unpack_error;
652 }
653 pcmk__set_rsc_flags(replica->container, pcmk_rsc_replica_container);
654 parent->children = g_list_append(parent->children, replica->container);
655
656 return pcmk_rc_ok;
657 }
658
659
660
661
662
663
664
665 static void
666 disallow_node(pcmk_resource_t *rsc, const char *uname)
667 {
668 gpointer match = g_hash_table_lookup(rsc->allowed_nodes, uname);
669
670 if (match) {
671 ((pcmk_node_t *) match)->weight = -PCMK_SCORE_INFINITY;
672 ((pcmk_node_t *) match)->rsc_discover_mode = pcmk_probe_never;
673 }
674 if (rsc->children) {
675 g_list_foreach(rsc->children, (GFunc) disallow_node, (gpointer) uname);
676 }
677 }
678
679 static int
680 create_remote_resource(pcmk_resource_t *parent, pe__bundle_variant_data_t *data,
681 pcmk__bundle_replica_t *replica)
682 {
683 if (replica->child && valid_network(data)) {
684 GHashTableIter gIter;
685 pcmk_node_t *node = NULL;
686 xmlNode *xml_remote = NULL;
687 char *id = crm_strdup_printf("%s-%d", data->prefix, replica->offset);
688 char *port_s = NULL;
689 const char *uname = NULL;
690 const char *connect_name = NULL;
691
692 if (pe_find_resource(parent->cluster->resources, id) != NULL) {
693 free(id);
694
695 id = crm_strdup_printf("pcmk-internal-%s-remote-%d",
696 replica->child->id, replica->offset);
697
698 pcmk__assert(pe_find_resource(parent->cluster->resources,
699 id) == NULL);
700 }
701
702
703
704
705
706 connect_name = (replica->ipaddr? replica->ipaddr : "#uname");
707
708 if (data->control_port == NULL) {
709 port_s = pcmk__itoa(DEFAULT_REMOTE_PORT);
710 }
711
712
713
714
715
716
717 xml_remote = pe_create_remote_xml(NULL, id, replica->container->id,
718 NULL, NULL, NULL,
719 connect_name, (data->control_port?
720 data->control_port : port_s));
721 free(port_s);
722
723
724
725
726
727 free(id);
728 id = NULL;
729 uname = pcmk__xe_id(xml_remote);
730
731
732
733
734
735 node = pcmk_find_node(parent->cluster, uname);
736 if (node == NULL) {
737 node = pe_create_node(uname, uname, PCMK_VALUE_REMOTE,
738 -PCMK_SCORE_INFINITY, parent->cluster);
739 } else {
740 node->weight = -PCMK_SCORE_INFINITY;
741 }
742 node->rsc_discover_mode = pcmk_probe_never;
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761 g_list_foreach(parent->cluster->resources, (GFunc) disallow_node,
762 (gpointer) uname);
763
764 replica->node = pe__copy_node(node);
765 replica->node->weight = 500;
766 replica->node->rsc_discover_mode = pcmk_probe_exclusive;
767
768
769 if (replica->child->allowed_nodes != NULL) {
770 g_hash_table_destroy(replica->child->allowed_nodes);
771 }
772 replica->child->allowed_nodes = pcmk__strkey_table(NULL, free);
773 g_hash_table_insert(replica->child->allowed_nodes,
774 (gpointer) replica->node->details->id,
775 pe__copy_node(replica->node));
776
777 {
778 pcmk_node_t *copy = pe__copy_node(replica->node);
779 copy->weight = -PCMK_SCORE_INFINITY;
780 g_hash_table_insert(replica->child->parent->allowed_nodes,
781 (gpointer) replica->node->details->id, copy);
782 }
783 if (pe__unpack_resource(xml_remote, &replica->remote, parent,
784 parent->cluster) != pcmk_rc_ok) {
785 return pcmk_rc_unpack_error;
786 }
787
788 g_hash_table_iter_init(&gIter, replica->remote->allowed_nodes);
789 while (g_hash_table_iter_next(&gIter, NULL, (void **)&node)) {
790 if (pcmk__is_pacemaker_remote_node(node)) {
791
792 node->weight = -PCMK_SCORE_INFINITY;
793 }
794 }
795
796 replica->node->details->remote_rsc = replica->remote;
797
798
799 replica->remote->container = replica->container;
800
801
802
803
804 pcmk__insert_dup(replica->node->details->attrs,
805 CRM_ATTR_KIND, "container");
806
807
808
809
810
811
812
813
814
815
816 parent->children = g_list_append(parent->children, replica->remote);
817 }
818 return pcmk_rc_ok;
819 }
820
821 static int
822 create_replica_resources(pcmk_resource_t *parent,
823 pe__bundle_variant_data_t *data,
824 pcmk__bundle_replica_t *replica)
825 {
826 int rc = pcmk_rc_ok;
827
828 rc = create_container_resource(parent, data, replica);
829 if (rc != pcmk_rc_ok) {
830 return rc;
831 }
832
833 rc = create_ip_resource(parent, data, replica);
834 if (rc != pcmk_rc_ok) {
835 return rc;
836 }
837
838 rc = create_remote_resource(parent, data, replica);
839 if (rc != pcmk_rc_ok) {
840 return rc;
841 }
842
843 if ((replica->child != NULL) && (replica->ipaddr != NULL)) {
844 pcmk__insert_meta(replica->child, "external-ip", replica->ipaddr);
845 }
846
847 if (replica->remote != NULL) {
848
849
850
851
852
853
854
855
856 pcmk__set_rsc_flags(replica->remote, pcmk_rsc_remote_nesting_allowed);
857 }
858 return rc;
859 }
860
861 static void
862 mount_add(pe__bundle_variant_data_t *bundle_data, const char *source,
863 const char *target, const char *options, uint32_t flags)
864 {
865 pe__bundle_mount_t *mount = pcmk__assert_alloc(1,
866 sizeof(pe__bundle_mount_t));
867
868 mount->source = pcmk__str_copy(source);
869 mount->target = pcmk__str_copy(target);
870 mount->options = pcmk__str_copy(options);
871 mount->flags = flags;
872 bundle_data->mounts = g_list_append(bundle_data->mounts, mount);
873 }
874
875 static void
876 mount_free(pe__bundle_mount_t *mount)
877 {
878 free(mount->source);
879 free(mount->target);
880 free(mount->options);
881 free(mount);
882 }
883
884 static void
885 port_free(pe__bundle_port_t *port)
886 {
887 free(port->source);
888 free(port->target);
889 free(port);
890 }
891
892 static pcmk__bundle_replica_t *
893 replica_for_remote(pcmk_resource_t *remote)
894 {
895 pcmk_resource_t *top = remote;
896 pe__bundle_variant_data_t *bundle_data = NULL;
897
898 if (top == NULL) {
899 return NULL;
900 }
901
902 while (top->parent != NULL) {
903 top = top->parent;
904 }
905
906 get_bundle_variant_data(bundle_data, top);
907 for (GList *gIter = bundle_data->replicas; gIter != NULL;
908 gIter = gIter->next) {
909 pcmk__bundle_replica_t *replica = gIter->data;
910
911 if (replica->remote == remote) {
912 return replica;
913 }
914 }
915 CRM_LOG_ASSERT(FALSE);
916 return NULL;
917 }
918
919 bool
920 pe__bundle_needs_remote_name(pcmk_resource_t *rsc)
921 {
922 const char *value;
923 GHashTable *params = NULL;
924
925 if (rsc == NULL) {
926 return false;
927 }
928
929
930 params = pe_rsc_params(rsc, NULL, rsc->cluster);
931 value = g_hash_table_lookup(params, PCMK_REMOTE_RA_ADDR);
932
933 return pcmk__str_eq(value, "#uname", pcmk__str_casei)
934 && xml_contains_remote_node(rsc->xml);
935 }
936
937 const char *
938 pe__add_bundle_remote_name(pcmk_resource_t *rsc, xmlNode *xml,
939 const char *field)
940 {
941
942
943 pcmk_node_t *node = NULL;
944 pcmk__bundle_replica_t *replica = NULL;
945
946 if (!pe__bundle_needs_remote_name(rsc)) {
947 return NULL;
948 }
949
950 replica = replica_for_remote(rsc);
951 if (replica == NULL) {
952 return NULL;
953 }
954
955 node = replica->container->allocated_to;
956 if (node == NULL) {
957
958
959
960 node = pcmk__current_node(replica->container);
961 }
962
963 if(node == NULL) {
964 crm_trace("Cannot determine address for bundle connection %s", rsc->id);
965 return NULL;
966 }
967
968 crm_trace("Setting address for bundle connection %s to bundle host %s",
969 rsc->id, pcmk__node_name(node));
970 if(xml != NULL && field != NULL) {
971 crm_xml_add(xml, field, node->details->uname);
972 }
973
974 return node->details->uname;
975 }
976
977 #define pe__set_bundle_mount_flags(mount_xml, flags, flags_to_set) do { \
978 flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, \
979 "Bundle mount", pcmk__xe_id(mount_xml), \
980 flags, (flags_to_set), #flags_to_set); \
981 } while (0)
982
983 gboolean
984 pe__unpack_bundle(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler)
985 {
986 const char *value = NULL;
987 xmlNode *xml_obj = NULL;
988 const xmlNode *xml_child = NULL;
989 xmlNode *xml_resource = NULL;
990 pe__bundle_variant_data_t *bundle_data = NULL;
991 bool need_log_mount = TRUE;
992
993 pcmk__assert(rsc != NULL);
994 pcmk__rsc_trace(rsc, "Processing resource %s...", rsc->id);
995
996 bundle_data = pcmk__assert_alloc(1, sizeof(pe__bundle_variant_data_t));
997 rsc->variant_opaque = bundle_data;
998 bundle_data->prefix = strdup(rsc->id);
999
1000 xml_obj = pcmk__xe_first_child(rsc->xml, PCMK_XE_DOCKER, NULL, NULL);
1001 if (xml_obj != NULL) {
1002 bundle_data->agent_type = PE__CONTAINER_AGENT_DOCKER;
1003 } else {
1004 xml_obj = pcmk__xe_first_child(rsc->xml, PCMK__XE_RKT, NULL, NULL);
1005 if (xml_obj != NULL) {
1006 pcmk__warn_once(pcmk__wo_rkt,
1007 "Support for " PCMK__XE_RKT " in bundles "
1008 "(such as %s) is deprecated and will be "
1009 "removed in a future release", rsc->id);
1010 bundle_data->agent_type = PE__CONTAINER_AGENT_RKT;
1011 } else {
1012 xml_obj = pcmk__xe_first_child(rsc->xml, PCMK_XE_PODMAN, NULL,
1013 NULL);
1014 if (xml_obj != NULL) {
1015 bundle_data->agent_type = PE__CONTAINER_AGENT_PODMAN;
1016 } else {
1017 return FALSE;
1018 }
1019 }
1020 }
1021
1022
1023 value = crm_element_value(xml_obj, PCMK_XA_PROMOTED_MAX);
1024 if (value == NULL) {
1025
1026 value = crm_element_value(xml_obj, PCMK__XA_PROMOTED_MAX_LEGACY);
1027
1028 if (value != NULL) {
1029 pcmk__warn_once(pcmk__wo_bundle_master,
1030 "Support for the " PCMK__XA_PROMOTED_MAX_LEGACY
1031 " attribute (such as in %s) is deprecated and "
1032 "will be removed in a future release. Use "
1033 PCMK_XA_PROMOTED_MAX " instead.",
1034 rsc->id);
1035 }
1036 }
1037 pcmk__scan_min_int(value, &bundle_data->promoted_max, 0);
1038
1039
1040
1041
1042 value = crm_element_value(xml_obj, PCMK_XA_REPLICAS);
1043 if ((value == NULL) && (bundle_data->promoted_max > 0)) {
1044 bundle_data->nreplicas = bundle_data->promoted_max;
1045 } else {
1046 pcmk__scan_min_int(value, &bundle_data->nreplicas, 1);
1047 }
1048
1049
1050
1051
1052
1053
1054 value = crm_element_value(xml_obj, PCMK_XA_REPLICAS_PER_HOST);
1055 pcmk__scan_min_int(value, &bundle_data->nreplicas_per_host, 1);
1056 if (bundle_data->nreplicas_per_host == 1) {
1057 pcmk__clear_rsc_flags(rsc, pcmk_rsc_unique);
1058 }
1059
1060 bundle_data->container_command =
1061 crm_element_value_copy(xml_obj, PCMK_XA_RUN_COMMAND);
1062 bundle_data->launcher_options = crm_element_value_copy(xml_obj,
1063 PCMK_XA_OPTIONS);
1064 bundle_data->image = crm_element_value_copy(xml_obj, PCMK_XA_IMAGE);
1065 bundle_data->container_network = crm_element_value_copy(xml_obj,
1066 PCMK_XA_NETWORK);
1067
1068 xml_obj = pcmk__xe_first_child(rsc->xml, PCMK_XE_NETWORK, NULL, NULL);
1069 if(xml_obj) {
1070 bundle_data->ip_range_start =
1071 crm_element_value_copy(xml_obj, PCMK_XA_IP_RANGE_START);
1072 bundle_data->host_netmask =
1073 crm_element_value_copy(xml_obj, PCMK_XA_HOST_NETMASK);
1074 bundle_data->host_network =
1075 crm_element_value_copy(xml_obj, PCMK_XA_HOST_INTERFACE);
1076 bundle_data->control_port =
1077 crm_element_value_copy(xml_obj, PCMK_XA_CONTROL_PORT);
1078 value = crm_element_value(xml_obj, PCMK_XA_ADD_HOST);
1079 if (crm_str_to_boolean(value, &bundle_data->add_host) != 1) {
1080 bundle_data->add_host = TRUE;
1081 }
1082
1083 for (xml_child = pcmk__xe_first_child(xml_obj, PCMK_XE_PORT_MAPPING,
1084 NULL, NULL);
1085 xml_child != NULL; xml_child = pcmk__xe_next_same(xml_child)) {
1086
1087 pe__bundle_port_t *port =
1088 pcmk__assert_alloc(1, sizeof(pe__bundle_port_t));
1089
1090 port->source = crm_element_value_copy(xml_child, PCMK_XA_PORT);
1091
1092 if(port->source == NULL) {
1093 port->source = crm_element_value_copy(xml_child, PCMK_XA_RANGE);
1094 } else {
1095 port->target = crm_element_value_copy(xml_child,
1096 PCMK_XA_INTERNAL_PORT);
1097 }
1098
1099 if(port->source != NULL && strlen(port->source) > 0) {
1100 if(port->target == NULL) {
1101 port->target = strdup(port->source);
1102 }
1103 bundle_data->ports = g_list_append(bundle_data->ports, port);
1104
1105 } else {
1106 pcmk__config_err("Invalid " PCMK_XA_PORT " directive %s",
1107 pcmk__xe_id(xml_child));
1108 port_free(port);
1109 }
1110 }
1111 }
1112
1113 xml_obj = pcmk__xe_first_child(rsc->xml, PCMK_XE_STORAGE, NULL, NULL);
1114 for (xml_child = pcmk__xe_first_child(xml_obj, PCMK_XE_STORAGE_MAPPING,
1115 NULL, NULL);
1116 xml_child != NULL; xml_child = pcmk__xe_next_same(xml_child)) {
1117
1118 const char *source = crm_element_value(xml_child, PCMK_XA_SOURCE_DIR);
1119 const char *target = crm_element_value(xml_child, PCMK_XA_TARGET_DIR);
1120 const char *options = crm_element_value(xml_child, PCMK_XA_OPTIONS);
1121 int flags = pe__bundle_mount_none;
1122
1123 if (source == NULL) {
1124 source = crm_element_value(xml_child, PCMK_XA_SOURCE_DIR_ROOT);
1125 pe__set_bundle_mount_flags(xml_child, flags,
1126 pe__bundle_mount_subdir);
1127 }
1128
1129 if (source && target) {
1130 mount_add(bundle_data, source, target, options, flags);
1131 if (strcmp(target, "/var/log") == 0) {
1132 need_log_mount = FALSE;
1133 }
1134 } else {
1135 pcmk__config_err("Invalid mount directive %s",
1136 pcmk__xe_id(xml_child));
1137 }
1138 }
1139
1140 xml_obj = pcmk__xe_first_child(rsc->xml, PCMK_XE_PRIMITIVE, NULL, NULL);
1141 if (xml_obj && valid_network(bundle_data)) {
1142 char *value = NULL;
1143 xmlNode *xml_set = NULL;
1144
1145 xml_resource = pcmk__xe_create(NULL, PCMK_XE_CLONE);
1146
1147
1148
1149
1150
1151 crm_xml_set_id(xml_resource, "%s-%s", bundle_data->prefix,
1152 (bundle_data->promoted_max? "master"
1153 : (const char *)xml_resource->name));
1154
1155 xml_set = pcmk__xe_create(xml_resource, PCMK_XE_META_ATTRIBUTES);
1156 crm_xml_set_id(xml_set, "%s-%s-meta", bundle_data->prefix, xml_resource->name);
1157
1158 crm_create_nvpair_xml(xml_set, NULL,
1159 PCMK_META_ORDERED, PCMK_VALUE_TRUE);
1160
1161 value = pcmk__itoa(bundle_data->nreplicas);
1162 crm_create_nvpair_xml(xml_set, NULL, PCMK_META_CLONE_MAX, value);
1163 free(value);
1164
1165 value = pcmk__itoa(bundle_data->nreplicas_per_host);
1166 crm_create_nvpair_xml(xml_set, NULL, PCMK_META_CLONE_NODE_MAX, value);
1167 free(value);
1168
1169 crm_create_nvpair_xml(xml_set, NULL, PCMK_META_GLOBALLY_UNIQUE,
1170 pcmk__btoa(bundle_data->nreplicas_per_host > 1));
1171
1172 if (bundle_data->promoted_max) {
1173 crm_create_nvpair_xml(xml_set, NULL,
1174 PCMK_META_PROMOTABLE, PCMK_VALUE_TRUE);
1175
1176 value = pcmk__itoa(bundle_data->promoted_max);
1177 crm_create_nvpair_xml(xml_set, NULL, PCMK_META_PROMOTED_MAX, value);
1178 free(value);
1179 }
1180
1181
1182 pcmk__xml_copy(xml_resource, xml_obj);
1183
1184 } else if(xml_obj) {
1185 pcmk__config_err("Cannot control %s inside %s without either "
1186 PCMK_XA_IP_RANGE_START " or " PCMK_XA_CONTROL_PORT,
1187 rsc->id, pcmk__xe_id(xml_obj));
1188 return FALSE;
1189 }
1190
1191 if(xml_resource) {
1192 int lpc = 0;
1193 GList *childIter = NULL;
1194 pe__bundle_port_t *port = NULL;
1195 GString *buffer = NULL;
1196
1197 if (pe__unpack_resource(xml_resource, &(bundle_data->child), rsc,
1198 scheduler) != pcmk_rc_ok) {
1199 return FALSE;
1200 }
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223 mount_add(bundle_data, DEFAULT_REMOTE_KEY_LOCATION,
1224 DEFAULT_REMOTE_KEY_LOCATION, NULL, pe__bundle_mount_none);
1225
1226 if (need_log_mount) {
1227 mount_add(bundle_data, CRM_BUNDLE_DIR, "/var/log", NULL,
1228 pe__bundle_mount_subdir);
1229 }
1230
1231 port = pcmk__assert_alloc(1, sizeof(pe__bundle_port_t));
1232 if(bundle_data->control_port) {
1233 port->source = strdup(bundle_data->control_port);
1234 } else {
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244 port->source = pcmk__itoa(DEFAULT_REMOTE_PORT);
1245 }
1246 port->target = strdup(port->source);
1247 bundle_data->ports = g_list_append(bundle_data->ports, port);
1248
1249 buffer = g_string_sized_new(1024);
1250 for (childIter = bundle_data->child->children; childIter != NULL;
1251 childIter = childIter->next) {
1252
1253 pcmk__bundle_replica_t *replica = NULL;
1254
1255 replica = pcmk__assert_alloc(1, sizeof(pcmk__bundle_replica_t));
1256 replica->child = childIter->data;
1257 replica->child->exclusive_discover = TRUE;
1258 replica->offset = lpc++;
1259
1260
1261 if (pcmk_is_set(replica->child->flags, pcmk_rsc_notify)) {
1262 pcmk__set_rsc_flags(bundle_data->child, pcmk_rsc_notify);
1263 }
1264
1265 allocate_ip(bundle_data, replica, buffer);
1266 bundle_data->replicas = g_list_append(bundle_data->replicas,
1267 replica);
1268 bundle_data->attribute_target =
1269 g_hash_table_lookup(replica->child->meta,
1270 PCMK_META_CONTAINER_ATTRIBUTE_TARGET);
1271 }
1272 bundle_data->container_host_options = g_string_free(buffer, FALSE);
1273
1274 if (bundle_data->attribute_target) {
1275 pcmk__insert_dup(rsc->meta, PCMK_META_CONTAINER_ATTRIBUTE_TARGET,
1276 bundle_data->attribute_target);
1277 pcmk__insert_dup(bundle_data->child->meta,
1278 PCMK_META_CONTAINER_ATTRIBUTE_TARGET,
1279 bundle_data->attribute_target);
1280 }
1281
1282 } else {
1283
1284 GString *buffer = g_string_sized_new(1024);
1285
1286 for (int lpc = 0; lpc < bundle_data->nreplicas; lpc++) {
1287 pcmk__bundle_replica_t *replica = NULL;
1288
1289 replica = pcmk__assert_alloc(1, sizeof(pcmk__bundle_replica_t));
1290 replica->offset = lpc;
1291 allocate_ip(bundle_data, replica, buffer);
1292 bundle_data->replicas = g_list_append(bundle_data->replicas,
1293 replica);
1294 }
1295 bundle_data->container_host_options = g_string_free(buffer, FALSE);
1296 }
1297
1298 for (GList *gIter = bundle_data->replicas; gIter != NULL;
1299 gIter = gIter->next) {
1300 pcmk__bundle_replica_t *replica = gIter->data;
1301
1302 if (create_replica_resources(rsc, bundle_data, replica) != pcmk_rc_ok) {
1303 pcmk__config_err("Failed unpacking resource %s", rsc->id);
1304 rsc->fns->free(rsc);
1305 return FALSE;
1306 }
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324 if (replica->child != NULL) {
1325 GHashTable *empty = replica->container->utilization;
1326
1327 replica->container->utilization = replica->child->utilization;
1328 replica->child->utilization = empty;
1329 }
1330 }
1331
1332 if (bundle_data->child) {
1333 rsc->children = g_list_append(rsc->children, bundle_data->child);
1334 }
1335 return TRUE;
1336 }
1337
1338 static int
1339 replica_resource_active(pcmk_resource_t *rsc, gboolean all)
1340 {
1341 if (rsc) {
1342 gboolean child_active = rsc->fns->active(rsc, all);
1343
1344 if (child_active && !all) {
1345 return TRUE;
1346 } else if (!child_active && all) {
1347 return FALSE;
1348 }
1349 }
1350 return -1;
1351 }
1352
1353 gboolean
1354 pe__bundle_active(pcmk_resource_t *rsc, gboolean all)
1355 {
1356 pe__bundle_variant_data_t *bundle_data = NULL;
1357 GList *iter = NULL;
1358
1359 get_bundle_variant_data(bundle_data, rsc);
1360 for (iter = bundle_data->replicas; iter != NULL; iter = iter->next) {
1361 pcmk__bundle_replica_t *replica = iter->data;
1362 int rsc_active;
1363
1364 rsc_active = replica_resource_active(replica->ip, all);
1365 if (rsc_active >= 0) {
1366 return (gboolean) rsc_active;
1367 }
1368
1369 rsc_active = replica_resource_active(replica->child, all);
1370 if (rsc_active >= 0) {
1371 return (gboolean) rsc_active;
1372 }
1373
1374 rsc_active = replica_resource_active(replica->container, all);
1375 if (rsc_active >= 0) {
1376 return (gboolean) rsc_active;
1377 }
1378
1379 rsc_active = replica_resource_active(replica->remote, all);
1380 if (rsc_active >= 0) {
1381 return (gboolean) rsc_active;
1382 }
1383 }
1384
1385
1386
1387
1388
1389 return all;
1390 }
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401 pcmk_resource_t *
1402 pe__find_bundle_replica(const pcmk_resource_t *bundle, const pcmk_node_t *node)
1403 {
1404 pe__bundle_variant_data_t *bundle_data = NULL;
1405
1406 pcmk__assert((bundle != NULL) && (node != NULL));
1407
1408 get_bundle_variant_data(bundle_data, bundle);
1409 for (GList *gIter = bundle_data->replicas; gIter != NULL;
1410 gIter = gIter->next) {
1411 pcmk__bundle_replica_t *replica = gIter->data;
1412
1413 pcmk__assert((replica != NULL) && (replica->node != NULL));
1414 if (pcmk__same_node(replica->node, node)) {
1415 return replica->child;
1416 }
1417 }
1418 return NULL;
1419 }
1420
1421
1422
1423
1424
1425 static void
1426 print_rsc_in_list(pcmk_resource_t *rsc, const char *pre_text, long options,
1427 void *print_data)
1428 {
1429 if (rsc != NULL) {
1430 if (options & pe_print_html) {
1431 status_print("<li>");
1432 }
1433 rsc->fns->print(rsc, pre_text, options, print_data);
1434 if (options & pe_print_html) {
1435 status_print("</li>\n");
1436 }
1437 }
1438 }
1439
1440
1441
1442
1443
1444 static void
1445 bundle_print_xml(pcmk_resource_t *rsc, const char *pre_text, long options,
1446 void *print_data)
1447 {
1448 pe__bundle_variant_data_t *bundle_data = NULL;
1449 char *child_text = NULL;
1450 CRM_CHECK(rsc != NULL, return);
1451
1452 if (pre_text == NULL) {
1453 pre_text = "";
1454 }
1455 child_text = crm_strdup_printf("%s ", pre_text);
1456
1457 get_bundle_variant_data(bundle_data, rsc);
1458
1459 status_print("%s<bundle ", pre_text);
1460 status_print(PCMK_XA_ID "=\"%s\" ", rsc->id);
1461 status_print("type=\"%s\" ", container_agent_str(bundle_data->agent_type));
1462 status_print("image=\"%s\" ", bundle_data->image);
1463 status_print("unique=\"%s\" ",
1464 pcmk__flag_text(rsc->flags, pcmk_rsc_unique));
1465 status_print("managed=\"%s\" ",
1466 pcmk__flag_text(rsc->flags, pcmk_rsc_managed));
1467 status_print("failed=\"%s\" ",
1468 pcmk__flag_text(rsc->flags, pcmk_rsc_failed));
1469 status_print(">\n");
1470
1471 for (GList *gIter = bundle_data->replicas; gIter != NULL;
1472 gIter = gIter->next) {
1473 pcmk__bundle_replica_t *replica = gIter->data;
1474
1475 pcmk__assert(replica);
1476 status_print("%s <replica " PCMK_XA_ID "=\"%d\">\n",
1477 pre_text, replica->offset);
1478 print_rsc_in_list(replica->ip, child_text, options, print_data);
1479 print_rsc_in_list(replica->child, child_text, options, print_data);
1480 print_rsc_in_list(replica->container, child_text, options, print_data);
1481 print_rsc_in_list(replica->remote, child_text, options, print_data);
1482 status_print("%s </replica>\n", pre_text);
1483 }
1484 status_print("%s</bundle>\n", pre_text);
1485 free(child_text);
1486 }
1487
1488 PCMK__OUTPUT_ARGS("bundle", "uint32_t", "pcmk_resource_t *", "GList *",
1489 "GList *")
1490 int
1491 pe__bundle_xml(pcmk__output_t *out, va_list args)
1492 {
1493 uint32_t show_opts = va_arg(args, uint32_t);
1494 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
1495 GList *only_node = va_arg(args, GList *);
1496 GList *only_rsc = va_arg(args, GList *);
1497
1498 pe__bundle_variant_data_t *bundle_data = NULL;
1499 int rc = pcmk_rc_no_output;
1500 gboolean printed_header = FALSE;
1501 gboolean print_everything = TRUE;
1502
1503 const char *desc = NULL;
1504
1505 pcmk__assert(rsc != NULL);
1506
1507 get_bundle_variant_data(bundle_data, rsc);
1508
1509 if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
1510 return rc;
1511 }
1512
1513 print_everything = pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches);
1514
1515 for (GList *gIter = bundle_data->replicas; gIter != NULL;
1516 gIter = gIter->next) {
1517 pcmk__bundle_replica_t *replica = gIter->data;
1518 char *id = NULL;
1519 gboolean print_ip, print_child, print_ctnr, print_remote;
1520
1521 pcmk__assert(replica);
1522
1523 if (pcmk__rsc_filtered_by_node(replica->container, only_node)) {
1524 continue;
1525 }
1526
1527 print_ip = replica->ip != NULL &&
1528 !replica->ip->fns->is_filtered(replica->ip, only_rsc, print_everything);
1529 print_child = replica->child != NULL &&
1530 !replica->child->fns->is_filtered(replica->child, only_rsc, print_everything);
1531 print_ctnr = !replica->container->fns->is_filtered(replica->container, only_rsc, print_everything);
1532 print_remote = replica->remote != NULL &&
1533 !replica->remote->fns->is_filtered(replica->remote, only_rsc, print_everything);
1534
1535 if (!print_everything && !print_ip && !print_child && !print_ctnr && !print_remote) {
1536 continue;
1537 }
1538
1539 if (!printed_header) {
1540 const char *type = container_agent_str(bundle_data->agent_type);
1541 const char *unique = pcmk__flag_text(rsc->flags, pcmk_rsc_unique);
1542 const char *maintenance = pcmk__flag_text(rsc->flags,
1543 pcmk_rsc_maintenance);
1544 const char *managed = pcmk__flag_text(rsc->flags, pcmk_rsc_managed);
1545 const char *failed = pcmk__flag_text(rsc->flags, pcmk_rsc_failed);
1546
1547 printed_header = TRUE;
1548
1549 desc = pe__resource_description(rsc, show_opts);
1550
1551 rc = pe__name_and_nvpairs_xml(out, true, PCMK_XE_BUNDLE,
1552 PCMK_XA_ID, rsc->id,
1553 PCMK_XA_TYPE, type,
1554 PCMK_XA_IMAGE, bundle_data->image,
1555 PCMK_XA_UNIQUE, unique,
1556 PCMK_XA_MAINTENANCE, maintenance,
1557 PCMK_XA_MANAGED, managed,
1558 PCMK_XA_FAILED, failed,
1559 PCMK_XA_DESCRIPTION, desc,
1560 NULL);
1561 pcmk__assert(rc == pcmk_rc_ok);
1562 }
1563
1564 id = pcmk__itoa(replica->offset);
1565 rc = pe__name_and_nvpairs_xml(out, true, PCMK_XE_REPLICA,
1566 PCMK_XA_ID, id,
1567 NULL);
1568 free(id);
1569 pcmk__assert(rc == pcmk_rc_ok);
1570
1571 if (print_ip) {
1572 out->message(out, (const char *) replica->ip->xml->name, show_opts,
1573 replica->ip, only_node, only_rsc);
1574 }
1575
1576 if (print_child) {
1577 out->message(out, (const char *) replica->child->xml->name,
1578 show_opts, replica->child, only_node, only_rsc);
1579 }
1580
1581 if (print_ctnr) {
1582 out->message(out, (const char *) replica->container->xml->name,
1583 show_opts, replica->container, only_node, only_rsc);
1584 }
1585
1586 if (print_remote) {
1587 out->message(out, (const char *) replica->remote->xml->name,
1588 show_opts, replica->remote, only_node, only_rsc);
1589 }
1590
1591 pcmk__output_xml_pop_parent(out);
1592 }
1593
1594 if (printed_header) {
1595 pcmk__output_xml_pop_parent(out);
1596 }
1597
1598 return rc;
1599 }
1600
1601 static void
1602 pe__bundle_replica_output_html(pcmk__output_t *out,
1603 pcmk__bundle_replica_t *replica,
1604 pcmk_node_t *node, uint32_t show_opts)
1605 {
1606 pcmk_resource_t *rsc = replica->child;
1607
1608 int offset = 0;
1609 char buffer[LINE_MAX];
1610
1611 if(rsc == NULL) {
1612 rsc = replica->container;
1613 }
1614
1615 if (replica->remote) {
1616 offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
1617 rsc_printable_id(replica->remote));
1618 } else {
1619 offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
1620 rsc_printable_id(replica->container));
1621 }
1622 if (replica->ipaddr) {
1623 offset += snprintf(buffer + offset, LINE_MAX - offset, " (%s)",
1624 replica->ipaddr);
1625 }
1626
1627 pe__common_output_html(out, rsc, buffer, node, show_opts);
1628 }
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639 static const char *
1640 get_unmanaged_str(const pcmk_resource_t *rsc)
1641 {
1642 if (pcmk_is_set(rsc->flags, pcmk_rsc_maintenance)) {
1643 return " (maintenance)";
1644 }
1645 if (!pcmk_is_set(rsc->flags, pcmk_rsc_managed)) {
1646 return " (unmanaged)";
1647 }
1648 return "";
1649 }
1650
1651 PCMK__OUTPUT_ARGS("bundle", "uint32_t", "pcmk_resource_t *", "GList *",
1652 "GList *")
1653 int
1654 pe__bundle_html(pcmk__output_t *out, va_list args)
1655 {
1656 uint32_t show_opts = va_arg(args, uint32_t);
1657 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
1658 GList *only_node = va_arg(args, GList *);
1659 GList *only_rsc = va_arg(args, GList *);
1660
1661 const char *desc = NULL;
1662 pe__bundle_variant_data_t *bundle_data = NULL;
1663 int rc = pcmk_rc_no_output;
1664 gboolean print_everything = TRUE;
1665
1666 pcmk__assert(rsc != NULL);
1667
1668 get_bundle_variant_data(bundle_data, rsc);
1669
1670 desc = pe__resource_description(rsc, show_opts);
1671
1672 if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
1673 return rc;
1674 }
1675
1676 print_everything = pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches);
1677
1678 for (GList *gIter = bundle_data->replicas; gIter != NULL;
1679 gIter = gIter->next) {
1680 pcmk__bundle_replica_t *replica = gIter->data;
1681 gboolean print_ip, print_child, print_ctnr, print_remote;
1682
1683 pcmk__assert(replica);
1684
1685 if (pcmk__rsc_filtered_by_node(replica->container, only_node)) {
1686 continue;
1687 }
1688
1689 print_ip = replica->ip != NULL &&
1690 !replica->ip->fns->is_filtered(replica->ip, only_rsc, print_everything);
1691 print_child = replica->child != NULL &&
1692 !replica->child->fns->is_filtered(replica->child, only_rsc, print_everything);
1693 print_ctnr = !replica->container->fns->is_filtered(replica->container, only_rsc, print_everything);
1694 print_remote = replica->remote != NULL &&
1695 !replica->remote->fns->is_filtered(replica->remote, only_rsc, print_everything);
1696
1697 if (pcmk_is_set(show_opts, pcmk_show_implicit_rscs) ||
1698 (print_everything == FALSE && (print_ip || print_child || print_ctnr || print_remote))) {
1699
1700
1701
1702 uint32_t new_show_opts = show_opts | pcmk_show_implicit_rscs;
1703
1704 PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Container bundle%s: %s [%s]%s%s%s%s%s",
1705 (bundle_data->nreplicas > 1)? " set" : "",
1706 rsc->id, bundle_data->image,
1707 pcmk_is_set(rsc->flags, pcmk_rsc_unique)? " (unique)" : "",
1708 desc ? " (" : "", desc ? desc : "", desc ? ")" : "",
1709 get_unmanaged_str(rsc));
1710
1711 if (pcmk__list_of_multiple(bundle_data->replicas)) {
1712 out->begin_list(out, NULL, NULL, "Replica[%d]", replica->offset);
1713 }
1714
1715 if (print_ip) {
1716 out->message(out, (const char *) replica->ip->xml->name,
1717 new_show_opts, replica->ip, only_node, only_rsc);
1718 }
1719
1720 if (print_child) {
1721 out->message(out, (const char *) replica->child->xml->name,
1722 new_show_opts, replica->child, only_node,
1723 only_rsc);
1724 }
1725
1726 if (print_ctnr) {
1727 out->message(out, (const char *) replica->container->xml->name,
1728 new_show_opts, replica->container, only_node,
1729 only_rsc);
1730 }
1731
1732 if (print_remote) {
1733 out->message(out, (const char *) replica->remote->xml->name,
1734 new_show_opts, replica->remote, only_node,
1735 only_rsc);
1736 }
1737
1738 if (pcmk__list_of_multiple(bundle_data->replicas)) {
1739 out->end_list(out);
1740 }
1741 } else if (print_everything == FALSE && !(print_ip || print_child || print_ctnr || print_remote)) {
1742 continue;
1743 } else {
1744 PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Container bundle%s: %s [%s]%s%s%s%s%s",
1745 (bundle_data->nreplicas > 1)? " set" : "",
1746 rsc->id, bundle_data->image,
1747 pcmk_is_set(rsc->flags, pcmk_rsc_unique)? " (unique)" : "",
1748 desc ? " (" : "", desc ? desc : "", desc ? ")" : "",
1749 get_unmanaged_str(rsc));
1750
1751 pe__bundle_replica_output_html(out, replica,
1752 pcmk__current_node(replica->container),
1753 show_opts);
1754 }
1755 }
1756
1757 PCMK__OUTPUT_LIST_FOOTER(out, rc);
1758 return rc;
1759 }
1760
1761 static void
1762 pe__bundle_replica_output_text(pcmk__output_t *out,
1763 pcmk__bundle_replica_t *replica,
1764 pcmk_node_t *node, uint32_t show_opts)
1765 {
1766 const pcmk_resource_t *rsc = replica->child;
1767
1768 int offset = 0;
1769 char buffer[LINE_MAX];
1770
1771 if(rsc == NULL) {
1772 rsc = replica->container;
1773 }
1774
1775 if (replica->remote) {
1776 offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
1777 rsc_printable_id(replica->remote));
1778 } else {
1779 offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
1780 rsc_printable_id(replica->container));
1781 }
1782 if (replica->ipaddr) {
1783 offset += snprintf(buffer + offset, LINE_MAX - offset, " (%s)",
1784 replica->ipaddr);
1785 }
1786
1787 pe__common_output_text(out, rsc, buffer, node, show_opts);
1788 }
1789
1790 PCMK__OUTPUT_ARGS("bundle", "uint32_t", "pcmk_resource_t *", "GList *",
1791 "GList *")
1792 int
1793 pe__bundle_text(pcmk__output_t *out, va_list args)
1794 {
1795 uint32_t show_opts = va_arg(args, uint32_t);
1796 pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *);
1797 GList *only_node = va_arg(args, GList *);
1798 GList *only_rsc = va_arg(args, GList *);
1799
1800 const char *desc = NULL;
1801 pe__bundle_variant_data_t *bundle_data = NULL;
1802 int rc = pcmk_rc_no_output;
1803 gboolean print_everything = TRUE;
1804
1805 desc = pe__resource_description(rsc, show_opts);
1806
1807 get_bundle_variant_data(bundle_data, rsc);
1808
1809 pcmk__assert(rsc != NULL);
1810
1811 if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
1812 return rc;
1813 }
1814
1815 print_everything = pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches);
1816
1817 for (GList *gIter = bundle_data->replicas; gIter != NULL;
1818 gIter = gIter->next) {
1819 pcmk__bundle_replica_t *replica = gIter->data;
1820 gboolean print_ip, print_child, print_ctnr, print_remote;
1821
1822 pcmk__assert(replica);
1823
1824 if (pcmk__rsc_filtered_by_node(replica->container, only_node)) {
1825 continue;
1826 }
1827
1828 print_ip = replica->ip != NULL &&
1829 !replica->ip->fns->is_filtered(replica->ip, only_rsc, print_everything);
1830 print_child = replica->child != NULL &&
1831 !replica->child->fns->is_filtered(replica->child, only_rsc, print_everything);
1832 print_ctnr = !replica->container->fns->is_filtered(replica->container, only_rsc, print_everything);
1833 print_remote = replica->remote != NULL &&
1834 !replica->remote->fns->is_filtered(replica->remote, only_rsc, print_everything);
1835
1836 if (pcmk_is_set(show_opts, pcmk_show_implicit_rscs) ||
1837 (print_everything == FALSE && (print_ip || print_child || print_ctnr || print_remote))) {
1838
1839
1840
1841 uint32_t new_show_opts = show_opts | pcmk_show_implicit_rscs;
1842
1843 PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Container bundle%s: %s [%s]%s%s%s%s%s",
1844 (bundle_data->nreplicas > 1)? " set" : "",
1845 rsc->id, bundle_data->image,
1846 pcmk_is_set(rsc->flags, pcmk_rsc_unique)? " (unique)" : "",
1847 desc ? " (" : "", desc ? desc : "", desc ? ")" : "",
1848 get_unmanaged_str(rsc));
1849
1850 if (pcmk__list_of_multiple(bundle_data->replicas)) {
1851 out->list_item(out, NULL, "Replica[%d]", replica->offset);
1852 }
1853
1854 out->begin_list(out, NULL, NULL, NULL);
1855
1856 if (print_ip) {
1857 out->message(out, (const char *) replica->ip->xml->name,
1858 new_show_opts, replica->ip, only_node, only_rsc);
1859 }
1860
1861 if (print_child) {
1862 out->message(out, (const char *) replica->child->xml->name,
1863 new_show_opts, replica->child, only_node,
1864 only_rsc);
1865 }
1866
1867 if (print_ctnr) {
1868 out->message(out, (const char *) replica->container->xml->name,
1869 new_show_opts, replica->container, only_node,
1870 only_rsc);
1871 }
1872
1873 if (print_remote) {
1874 out->message(out, (const char *) replica->remote->xml->name,
1875 new_show_opts, replica->remote, only_node,
1876 only_rsc);
1877 }
1878
1879 out->end_list(out);
1880 } else if (print_everything == FALSE && !(print_ip || print_child || print_ctnr || print_remote)) {
1881 continue;
1882 } else {
1883 PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Container bundle%s: %s [%s]%s%s%s%s%s",
1884 (bundle_data->nreplicas > 1)? " set" : "",
1885 rsc->id, bundle_data->image,
1886 pcmk_is_set(rsc->flags, pcmk_rsc_unique)? " (unique)" : "",
1887 desc ? " (" : "", desc ? desc : "", desc ? ")" : "",
1888 get_unmanaged_str(rsc));
1889
1890 pe__bundle_replica_output_text(out, replica,
1891 pcmk__current_node(replica->container),
1892 show_opts);
1893 }
1894 }
1895
1896 PCMK__OUTPUT_LIST_FOOTER(out, rc);
1897 return rc;
1898 }
1899
1900
1901
1902
1903
1904 static void
1905 print_bundle_replica(pcmk__bundle_replica_t *replica, const char *pre_text,
1906 long options, void *print_data)
1907 {
1908 pcmk_node_t *node = NULL;
1909 pcmk_resource_t *rsc = replica->child;
1910
1911 int offset = 0;
1912 char buffer[LINE_MAX];
1913
1914 if(rsc == NULL) {
1915 rsc = replica->container;
1916 }
1917
1918 if (replica->remote) {
1919 offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
1920 rsc_printable_id(replica->remote));
1921 } else {
1922 offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
1923 rsc_printable_id(replica->container));
1924 }
1925 if (replica->ipaddr) {
1926 offset += snprintf(buffer + offset, LINE_MAX - offset, " (%s)",
1927 replica->ipaddr);
1928 }
1929
1930 node = pcmk__current_node(replica->container);
1931 common_print(rsc, pre_text, buffer, node, options, print_data);
1932 }
1933
1934
1935
1936
1937
1938 void
1939 pe__print_bundle(pcmk_resource_t *rsc, const char *pre_text, long options,
1940 void *print_data)
1941 {
1942 pe__bundle_variant_data_t *bundle_data = NULL;
1943 char *child_text = NULL;
1944 CRM_CHECK(rsc != NULL, return);
1945
1946 if (options & pe_print_xml) {
1947 bundle_print_xml(rsc, pre_text, options, print_data);
1948 return;
1949 }
1950
1951 get_bundle_variant_data(bundle_data, rsc);
1952
1953 if (pre_text == NULL) {
1954 pre_text = " ";
1955 }
1956
1957 status_print("%sContainer bundle%s: %s [%s]%s%s\n",
1958 pre_text, ((bundle_data->nreplicas > 1)? " set" : ""),
1959 rsc->id, bundle_data->image,
1960 pcmk_is_set(rsc->flags, pcmk_rsc_unique)? " (unique)" : "",
1961 pcmk_is_set(rsc->flags, pcmk_rsc_managed)? "" : " (unmanaged)");
1962 if (options & pe_print_html) {
1963 status_print("<br />\n<ul>\n");
1964 }
1965
1966
1967 for (GList *gIter = bundle_data->replicas; gIter != NULL;
1968 gIter = gIter->next) {
1969 pcmk__bundle_replica_t *replica = gIter->data;
1970
1971 pcmk__assert(replica);
1972 if (options & pe_print_html) {
1973 status_print("<li>");
1974 }
1975
1976 if (pcmk_is_set(options, pe_print_implicit)) {
1977 child_text = crm_strdup_printf(" %s", pre_text);
1978 if (pcmk__list_of_multiple(bundle_data->replicas)) {
1979 status_print(" %sReplica[%d]\n", pre_text, replica->offset);
1980 }
1981 if (options & pe_print_html) {
1982 status_print("<br />\n<ul>\n");
1983 }
1984 print_rsc_in_list(replica->ip, child_text, options, print_data);
1985 print_rsc_in_list(replica->container, child_text, options, print_data);
1986 print_rsc_in_list(replica->remote, child_text, options, print_data);
1987 print_rsc_in_list(replica->child, child_text, options, print_data);
1988 if (options & pe_print_html) {
1989 status_print("</ul>\n");
1990 }
1991 } else {
1992 child_text = crm_strdup_printf("%s ", pre_text);
1993 print_bundle_replica(replica, child_text, options, print_data);
1994 }
1995 free(child_text);
1996
1997 if (options & pe_print_html) {
1998 status_print("</li>\n");
1999 }
2000 }
2001 if (options & pe_print_html) {
2002 status_print("</ul>\n");
2003 }
2004 }
2005
2006 static void
2007 free_bundle_replica(pcmk__bundle_replica_t *replica)
2008 {
2009 if (replica == NULL) {
2010 return;
2011 }
2012
2013 if (replica->node) {
2014 free(replica->node);
2015 replica->node = NULL;
2016 }
2017
2018 if (replica->ip) {
2019 free_xml(replica->ip->xml);
2020 replica->ip->xml = NULL;
2021 replica->ip->fns->free(replica->ip);
2022 replica->ip = NULL;
2023 }
2024 if (replica->container) {
2025 free_xml(replica->container->xml);
2026 replica->container->xml = NULL;
2027 replica->container->fns->free(replica->container);
2028 replica->container = NULL;
2029 }
2030 if (replica->remote) {
2031 free_xml(replica->remote->xml);
2032 replica->remote->xml = NULL;
2033 replica->remote->fns->free(replica->remote);
2034 replica->remote = NULL;
2035 }
2036 free(replica->ipaddr);
2037 free(replica);
2038 }
2039
2040 void
2041 pe__free_bundle(pcmk_resource_t *rsc)
2042 {
2043 pe__bundle_variant_data_t *bundle_data = NULL;
2044 CRM_CHECK(rsc != NULL, return);
2045
2046 get_bundle_variant_data(bundle_data, rsc);
2047 pcmk__rsc_trace(rsc, "Freeing %s", rsc->id);
2048
2049 free(bundle_data->prefix);
2050 free(bundle_data->image);
2051 free(bundle_data->control_port);
2052 free(bundle_data->host_network);
2053 free(bundle_data->host_netmask);
2054 free(bundle_data->ip_range_start);
2055 free(bundle_data->container_network);
2056 free(bundle_data->launcher_options);
2057 free(bundle_data->container_command);
2058 g_free(bundle_data->container_host_options);
2059
2060 g_list_free_full(bundle_data->replicas,
2061 (GDestroyNotify) free_bundle_replica);
2062 g_list_free_full(bundle_data->mounts, (GDestroyNotify)mount_free);
2063 g_list_free_full(bundle_data->ports, (GDestroyNotify)port_free);
2064 g_list_free(rsc->children);
2065
2066 if(bundle_data->child) {
2067 free_xml(bundle_data->child->xml);
2068 bundle_data->child->xml = NULL;
2069 bundle_data->child->fns->free(bundle_data->child);
2070 }
2071 common_free(rsc);
2072 }
2073
2074 enum rsc_role_e
2075 pe__bundle_resource_state(const pcmk_resource_t *rsc, gboolean current)
2076 {
2077 enum rsc_role_e container_role = pcmk_role_unknown;
2078 return container_role;
2079 }
2080
2081
2082
2083
2084
2085
2086
2087
2088 int
2089 pe_bundle_replicas(const pcmk_resource_t *rsc)
2090 {
2091 if (pcmk__is_bundle(rsc)) {
2092 pe__bundle_variant_data_t *bundle_data = NULL;
2093
2094 get_bundle_variant_data(bundle_data, rsc);
2095 return bundle_data->nreplicas;
2096 }
2097 return 0;
2098 }
2099
2100 void
2101 pe__count_bundle(pcmk_resource_t *rsc)
2102 {
2103 pe__bundle_variant_data_t *bundle_data = NULL;
2104
2105 get_bundle_variant_data(bundle_data, rsc);
2106 for (GList *item = bundle_data->replicas; item != NULL; item = item->next) {
2107 pcmk__bundle_replica_t *replica = item->data;
2108
2109 if (replica->ip) {
2110 replica->ip->fns->count(replica->ip);
2111 }
2112 if (replica->child) {
2113 replica->child->fns->count(replica->child);
2114 }
2115 if (replica->container) {
2116 replica->container->fns->count(replica->container);
2117 }
2118 if (replica->remote) {
2119 replica->remote->fns->count(replica->remote);
2120 }
2121 }
2122 }
2123
2124 gboolean
2125 pe__bundle_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc,
2126 gboolean check_parent)
2127 {
2128 gboolean passes = FALSE;
2129 pe__bundle_variant_data_t *bundle_data = NULL;
2130
2131 if (pcmk__str_in_list(rsc_printable_id(rsc), only_rsc, pcmk__str_star_matches)) {
2132 passes = TRUE;
2133 } else {
2134 get_bundle_variant_data(bundle_data, rsc);
2135
2136 for (GList *gIter = bundle_data->replicas; gIter != NULL; gIter = gIter->next) {
2137 pcmk__bundle_replica_t *replica = gIter->data;
2138
2139 if (replica->ip != NULL && !replica->ip->fns->is_filtered(replica->ip, only_rsc, FALSE)) {
2140 passes = TRUE;
2141 break;
2142 } else if (replica->child != NULL && !replica->child->fns->is_filtered(replica->child, only_rsc, FALSE)) {
2143 passes = TRUE;
2144 break;
2145 } else if (!replica->container->fns->is_filtered(replica->container, only_rsc, FALSE)) {
2146 passes = TRUE;
2147 break;
2148 } else if (replica->remote != NULL && !replica->remote->fns->is_filtered(replica->remote, only_rsc, FALSE)) {
2149 passes = TRUE;
2150 break;
2151 }
2152 }
2153 }
2154
2155 return !passes;
2156 }
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168 GList *
2169 pe__bundle_containers(const pcmk_resource_t *bundle)
2170 {
2171 GList *containers = NULL;
2172 const pe__bundle_variant_data_t *data = NULL;
2173
2174 get_bundle_variant_data(data, bundle);
2175 for (GList *iter = data->replicas; iter != NULL; iter = iter->next) {
2176 pcmk__bundle_replica_t *replica = iter->data;
2177
2178 containers = g_list_append(containers, replica->container);
2179 }
2180 return containers;
2181 }
2182
2183
2184 pcmk_node_t *
2185 pe__bundle_active_node(const pcmk_resource_t *rsc, unsigned int *count_all,
2186 unsigned int *count_clean)
2187 {
2188 pcmk_node_t *active = NULL;
2189 pcmk_node_t *node = NULL;
2190 pcmk_resource_t *container = NULL;
2191 GList *containers = NULL;
2192 GList *iter = NULL;
2193 GHashTable *nodes = NULL;
2194 const pe__bundle_variant_data_t *data = NULL;
2195
2196 if (count_all != NULL) {
2197 *count_all = 0;
2198 }
2199 if (count_clean != NULL) {
2200 *count_clean = 0;
2201 }
2202 if (rsc == NULL) {
2203 return NULL;
2204 }
2205
2206
2207
2208
2209 get_bundle_variant_data(data, rsc);
2210 for (iter = data->replicas; iter != NULL; iter = iter->next) {
2211 pcmk__bundle_replica_t *replica = iter->data;
2212
2213 if (replica->container->running_on != NULL) {
2214 containers = g_list_append(containers, replica->container);
2215 }
2216 }
2217 if (containers == NULL) {
2218 return NULL;
2219 }
2220
2221
2222
2223
2224
2225
2226
2227 if (pcmk__list_of_1(containers)) {
2228 container = containers->data;
2229 node = container->fns->active_node(container, count_all, count_clean);
2230 g_list_free(containers);
2231 return node;
2232 }
2233
2234
2235 nodes = g_hash_table_new(NULL, NULL);
2236 for (iter = containers; iter != NULL; iter = iter->next) {
2237 container = iter->data;
2238
2239 for (GList *node_iter = container->running_on; node_iter != NULL;
2240 node_iter = node_iter->next) {
2241 node = node_iter->data;
2242
2243
2244 if (g_hash_table_insert(nodes, (gpointer) node->details,
2245 (gpointer) node)
2246 && !pe__count_active_node(rsc, node, &active, count_all,
2247 count_clean)) {
2248 goto done;
2249 }
2250 }
2251 }
2252
2253 done:
2254 g_list_free(containers);
2255 g_hash_table_destroy(nodes);
2256 return active;
2257 }
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267 unsigned int
2268 pe__bundle_max_per_node(const pcmk_resource_t *rsc)
2269 {
2270 pe__bundle_variant_data_t *bundle_data = NULL;
2271
2272 get_bundle_variant_data(bundle_data, rsc);
2273 pcmk__assert(bundle_data->nreplicas_per_host >= 0);
2274 return (unsigned int) bundle_data->nreplicas_per_host;
2275 }