pacemaker  2.1.5-b7adf64e51
Scalable High-Availability cluster resource manager
bundle.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2022 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU Lesser General Public License
7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
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/msg_xml.h>
19 #include <crm/common/output.h>
21 #include <pe_status_private.h>
22 
23 #define PE__VARIANT_BUNDLE 1
24 #include "./variant.h"
25 
26 static char *
27 next_ip(const char *last_ip)
28 {
29  unsigned int oct1 = 0;
30  unsigned int oct2 = 0;
31  unsigned int oct3 = 0;
32  unsigned int oct4 = 0;
33  int rc = sscanf(last_ip, "%u.%u.%u.%u", &oct1, &oct2, &oct3, &oct4);
34 
35  if (rc != 4) {
36  /*@ TODO check for IPv6 */
37  return NULL;
38 
39  } else if (oct3 > 253) {
40  return NULL;
41 
42  } else if (oct4 > 253) {
43  ++oct3;
44  oct4 = 1;
45 
46  } else {
47  ++oct4;
48  }
49 
50  return crm_strdup_printf("%u.%u.%u.%u", oct1, oct2, oct3, oct4);
51 }
52 
53 static void
54 allocate_ip(pe__bundle_variant_data_t *data, pe__bundle_replica_t *replica,
55  GString *buffer)
56 {
57  if(data->ip_range_start == NULL) {
58  return;
59 
60  } else if(data->ip_last) {
61  replica->ipaddr = next_ip(data->ip_last);
62 
63  } else {
64  replica->ipaddr = strdup(data->ip_range_start);
65  }
66 
67  data->ip_last = replica->ipaddr;
68  switch (data->agent_type) {
69  case PE__CONTAINER_AGENT_DOCKER:
70  case PE__CONTAINER_AGENT_PODMAN:
71  if (data->add_host) {
72  g_string_append_printf(buffer, " --add-host=%s-%d:%s",
73  data->prefix, replica->offset,
74  replica->ipaddr);
75  } else {
76  g_string_append_printf(buffer, " --hosts-entry=%s=%s-%d",
77  replica->ipaddr, data->prefix,
78  replica->offset);
79  }
80  break;
81 
82  case PE__CONTAINER_AGENT_RKT:
83  g_string_append_printf(buffer, " --hosts-entry=%s=%s-%d",
84  replica->ipaddr, data->prefix,
85  replica->offset);
86  break;
87 
88  default: // PE__CONTAINER_AGENT_UNKNOWN
89  break;
90  }
91 }
92 
93 static xmlNode *
94 create_resource(const char *name, const char *provider, const char *kind)
95 {
96  xmlNode *rsc = create_xml_node(NULL, XML_CIB_TAG_RESOURCE);
97 
100  crm_xml_add(rsc, XML_AGENT_ATTR_PROVIDER, provider);
101  crm_xml_add(rsc, XML_ATTR_TYPE, kind);
102 
103  return rsc;
104 }
105 
118 static bool
119 valid_network(pe__bundle_variant_data_t *data)
120 {
121  if(data->ip_range_start) {
122  return TRUE;
123  }
124  if(data->control_port) {
125  if(data->nreplicas_per_host > 1) {
126  pe_err("Specifying the 'control-port' for %s requires 'replicas-per-host=1'", data->prefix);
127  data->nreplicas_per_host = 1;
128  // @TODO to be sure: pe__clear_resource_flags(rsc, pe_rsc_unique);
129  }
130  return TRUE;
131  }
132  return FALSE;
133 }
134 
135 static int
136 create_ip_resource(pe_resource_t *parent, pe__bundle_variant_data_t *data,
137  pe__bundle_replica_t *replica)
138 {
139  if(data->ip_range_start) {
140  char *id = NULL;
141  xmlNode *xml_ip = NULL;
142  xmlNode *xml_obj = NULL;
143 
144  id = crm_strdup_printf("%s-ip-%s", data->prefix, replica->ipaddr);
146  xml_ip = create_resource(id, "heartbeat", "IPaddr2");
147  free(id);
148 
149  xml_obj = create_xml_node(xml_ip, XML_TAG_ATTR_SETS);
150  crm_xml_set_id(xml_obj, "%s-attributes-%d",
151  data->prefix, replica->offset);
152 
153  crm_create_nvpair_xml(xml_obj, NULL, "ip", replica->ipaddr);
154  if(data->host_network) {
155  crm_create_nvpair_xml(xml_obj, NULL, "nic", data->host_network);
156  }
157 
158  if(data->host_netmask) {
159  crm_create_nvpair_xml(xml_obj, NULL,
160  "cidr_netmask", data->host_netmask);
161 
162  } else {
163  crm_create_nvpair_xml(xml_obj, NULL, "cidr_netmask", "32");
164  }
165 
166  xml_obj = create_xml_node(xml_ip, "operations");
167  crm_create_op_xml(xml_obj, ID(xml_ip), "monitor", "60s", NULL);
168 
169  // TODO: Other ops? Timeouts and intervals from underlying resource?
170 
171  if (pe__unpack_resource(xml_ip, &replica->ip, parent,
172  parent->cluster) != pcmk_rc_ok) {
173  return pcmk_rc_unpack_error;
174  }
175 
176  parent->children = g_list_append(parent->children, replica->ip);
177  }
178  return pcmk_rc_ok;
179 }
180 
181 static const char*
182 container_agent_str(enum pe__container_agent t)
183 {
184  switch (t) {
185  case PE__CONTAINER_AGENT_DOCKER: return PE__CONTAINER_AGENT_DOCKER_S;
186  case PE__CONTAINER_AGENT_RKT: return PE__CONTAINER_AGENT_RKT_S;
187  case PE__CONTAINER_AGENT_PODMAN: return PE__CONTAINER_AGENT_PODMAN_S;
188  default: // PE__CONTAINER_AGENT_UNKNOWN
189  break;
190  }
191  return PE__CONTAINER_AGENT_UNKNOWN_S;
192 }
193 
194 static int
195 create_container_resource(pe_resource_t *parent,
196  const pe__bundle_variant_data_t *data,
197  pe__bundle_replica_t *replica)
198 {
199  char *id = NULL;
200  xmlNode *xml_container = NULL;
201  xmlNode *xml_obj = NULL;
202 
203  // Agent-specific
204  const char *hostname_opt = NULL;
205  const char *env_opt = NULL;
206  const char *agent_str = NULL;
207  int volid = 0; // rkt-only
208 
209  GString *buffer = NULL;
210  GString *dbuffer = NULL;
211 
212  // Where syntax differences are drop-in replacements, set them now
213  switch (data->agent_type) {
214  case PE__CONTAINER_AGENT_DOCKER:
215  case PE__CONTAINER_AGENT_PODMAN:
216  hostname_opt = "-h ";
217  env_opt = "-e ";
218  break;
219  case PE__CONTAINER_AGENT_RKT:
220  hostname_opt = "--hostname=";
221  env_opt = "--environment=";
222  break;
223  default: // PE__CONTAINER_AGENT_UNKNOWN
224  return pcmk_rc_unpack_error;
225  }
226  agent_str = container_agent_str(data->agent_type);
227 
228  buffer = g_string_sized_new(4096);
229 
230  id = crm_strdup_printf("%s-%s-%d", data->prefix, agent_str,
231  replica->offset);
233  xml_container = create_resource(id, "heartbeat", agent_str);
234  free(id);
235 
236  xml_obj = create_xml_node(xml_container, XML_TAG_ATTR_SETS);
237  crm_xml_set_id(xml_obj, "%s-attributes-%d", data->prefix, replica->offset);
238 
239  crm_create_nvpair_xml(xml_obj, NULL, "image", data->image);
240  crm_create_nvpair_xml(xml_obj, NULL, "allow_pull", XML_BOOLEAN_TRUE);
241  crm_create_nvpair_xml(xml_obj, NULL, "force_kill", XML_BOOLEAN_FALSE);
242  crm_create_nvpair_xml(xml_obj, NULL, "reuse", XML_BOOLEAN_FALSE);
243 
244  if (data->agent_type == PE__CONTAINER_AGENT_DOCKER) {
245  g_string_append(buffer, " --restart=no");
246  }
247 
248  /* Set a container hostname only if we have an IP to map it to. The user can
249  * set -h or --uts=host themselves if they want a nicer name for logs, but
250  * this makes applications happy who need their hostname to match the IP
251  * they bind to.
252  */
253  if (data->ip_range_start != NULL) {
254  g_string_append_printf(buffer, " %s%s-%d", hostname_opt, data->prefix,
255  replica->offset);
256  }
257  pcmk__g_strcat(buffer, " ", env_opt, "PCMK_stderr=1", NULL);
258 
259  if (data->container_network != NULL) {
260  pcmk__g_strcat(buffer, " --net=", data->container_network, NULL);
261  }
262 
263  if (data->control_port != NULL) {
264  pcmk__g_strcat(buffer, " ", env_opt, "PCMK_remote_port=",
265  data->control_port, NULL);
266  } else {
267  g_string_append_printf(buffer, " %sPCMK_remote_port=%d", env_opt,
269  }
270 
271  for (GList *iter = data->mounts; iter != NULL; iter = iter->next) {
272  pe__bundle_mount_t *mount = (pe__bundle_mount_t *) iter->data;
273  char *source = NULL;
274 
275  if (pcmk_is_set(mount->flags, pe__bundle_mount_subdir)) {
276  source = crm_strdup_printf("%s/%s-%d", mount->source, data->prefix,
277  replica->offset);
278  pcmk__add_separated_word(&dbuffer, 1024, source, ",");
279  }
280 
281  switch (data->agent_type) {
282  case PE__CONTAINER_AGENT_DOCKER:
283  case PE__CONTAINER_AGENT_PODMAN:
284  pcmk__g_strcat(buffer,
285  " -v ", pcmk__s(source, mount->source),
286  ":", mount->target, NULL);
287 
288  if (mount->options != NULL) {
289  pcmk__g_strcat(buffer, ":", mount->options, NULL);
290  }
291  break;
292  case PE__CONTAINER_AGENT_RKT:
293  g_string_append_printf(buffer,
294  " --volume vol%d,kind=host,"
295  "source=%s%s%s "
296  "--mount volume=vol%d,target=%s",
297  volid, pcmk__s(source, mount->source),
298  (mount->options != NULL)? "," : "",
299  pcmk__s(mount->options, ""),
300  volid, mount->target);
301  volid++;
302  break;
303  default:
304  break;
305  }
306  free(source);
307  }
308 
309  for (GList *iter = data->ports; iter != NULL; iter = iter->next) {
310  pe__bundle_port_t *port = (pe__bundle_port_t *) iter->data;
311 
312  switch (data->agent_type) {
313  case PE__CONTAINER_AGENT_DOCKER:
314  case PE__CONTAINER_AGENT_PODMAN:
315  if (replica->ipaddr != NULL) {
316  pcmk__g_strcat(buffer,
317  " -p ", replica->ipaddr, ":", port->source,
318  ":", port->target, NULL);
319 
320  } else if (!pcmk__str_eq(data->container_network, "host",
321  pcmk__str_none)) {
322  // No need to do port mapping if net == host
323  pcmk__g_strcat(buffer,
324  " -p ", port->source, ":", port->target,
325  NULL);
326  }
327  break;
328  case PE__CONTAINER_AGENT_RKT:
329  if (replica->ipaddr != NULL) {
330  pcmk__g_strcat(buffer,
331  " --port=", port->target,
332  ":", replica->ipaddr, ":", port->source,
333  NULL);
334  } else {
335  pcmk__g_strcat(buffer,
336  " --port=", port->target, ":", port->source,
337  NULL);
338  }
339  break;
340  default:
341  break;
342  }
343  }
344 
345  /* @COMPAT: We should use pcmk__add_word() here, but we can't yet, because
346  * it would cause restarts during rolling upgrades.
347  *
348  * In a previous version of the container resource creation logic, if
349  * data->launcher_options is not NULL, we append
350  * (" %s", data->launcher_options) even if data->launcher_options is an
351  * empty string. Likewise for data->container_host_options. Using
352  *
353  * pcmk__add_word(buffer, 0, data->launcher_options)
354  *
355  * removes that extra trailing space, causing a resource definition change.
356  */
357  if (data->launcher_options != NULL) {
358  pcmk__g_strcat(buffer, " ", data->launcher_options, NULL);
359  }
360 
361  if (data->container_host_options != NULL) {
362  pcmk__g_strcat(buffer, " ", data->container_host_options, NULL);
363  }
364 
365  crm_create_nvpair_xml(xml_obj, NULL, "run_opts",
366  (const char *) buffer->str);
367  g_string_free(buffer, TRUE);
368 
369  crm_create_nvpair_xml(xml_obj, NULL, "mount_points",
370  (dbuffer != NULL)? (const char *) dbuffer->str : "");
371  if (dbuffer != NULL) {
372  g_string_free(dbuffer, TRUE);
373  }
374 
375  if (replica->child != NULL) {
376  if (data->container_command != NULL) {
377  crm_create_nvpair_xml(xml_obj, NULL, "run_cmd",
378  data->container_command);
379  } else {
380  crm_create_nvpair_xml(xml_obj, NULL, "run_cmd",
381  SBIN_DIR "/pacemaker-remoted");
382  }
383 
384  /* TODO: Allow users to specify their own?
385  *
386  * We just want to know if the container is alive; we'll monitor the
387  * child independently.
388  */
389  crm_create_nvpair_xml(xml_obj, NULL, "monitor_cmd", "/bin/true");
390 #if 0
391  /* @TODO Consider supporting the use case where we can start and stop
392  * resources, but not proxy local commands (such as setting node
393  * attributes), by running the local executor in stand-alone mode.
394  * However, this would probably be better done via ACLs as with other
395  * Pacemaker Remote nodes.
396  */
397  } else if ((child != NULL) && data->untrusted) {
398  crm_create_nvpair_xml(xml_obj, NULL, "run_cmd",
399  CRM_DAEMON_DIR "/pacemaker-execd");
400  crm_create_nvpair_xml(xml_obj, NULL, "monitor_cmd",
401  CRM_DAEMON_DIR "/pacemaker/cts-exec-helper -c poke");
402 #endif
403  } else {
404  if (data->container_command != NULL) {
405  crm_create_nvpair_xml(xml_obj, NULL, "run_cmd",
406  data->container_command);
407  }
408 
409  /* TODO: Allow users to specify their own?
410  *
411  * We don't know what's in the container, so we just want to know if it
412  * is alive.
413  */
414  crm_create_nvpair_xml(xml_obj, NULL, "monitor_cmd", "/bin/true");
415  }
416 
417  xml_obj = create_xml_node(xml_container, "operations");
418  crm_create_op_xml(xml_obj, ID(xml_container), "monitor", "60s", NULL);
419 
420  // TODO: Other ops? Timeouts and intervals from underlying resource?
421  if (pe__unpack_resource(xml_container, &replica->container, parent,
422  parent->cluster) != pcmk_rc_ok) {
423  return pcmk_rc_unpack_error;
424  }
425  parent->children = g_list_append(parent->children, replica->container);
426 
427  return pcmk_rc_ok;
428 }
429 
436 static void
437 disallow_node(pe_resource_t *rsc, const char *uname)
438 {
439  gpointer match = g_hash_table_lookup(rsc->allowed_nodes, uname);
440 
441  if (match) {
442  ((pe_node_t *) match)->weight = -INFINITY;
443  ((pe_node_t *) match)->rsc_discover_mode = pe_discover_never;
444  }
445  if (rsc->children) {
446  g_list_foreach(rsc->children, (GFunc) disallow_node, (gpointer) uname);
447  }
448 }
449 
450 static int
451 create_remote_resource(pe_resource_t *parent, pe__bundle_variant_data_t *data,
452  pe__bundle_replica_t *replica)
453 {
454  if (replica->child && valid_network(data)) {
455  GHashTableIter gIter;
456  pe_node_t *node = NULL;
457  xmlNode *xml_remote = NULL;
458  char *id = crm_strdup_printf("%s-%d", data->prefix, replica->offset);
459  char *port_s = NULL;
460  const char *uname = NULL;
461  const char *connect_name = NULL;
462 
463  if (pe_find_resource(parent->cluster->resources, id) != NULL) {
464  free(id);
465  // The biggest hammer we have
466  id = crm_strdup_printf("pcmk-internal-%s-remote-%d",
467  replica->child->id, replica->offset);
468  //@TODO return error instead of asserting?
469  CRM_ASSERT(pe_find_resource(parent->cluster->resources,
470  id) == NULL);
471  }
472 
473  /* REMOTE_CONTAINER_HACK: Using "#uname" as the server name when the
474  * connection does not have its own IP is a magic string that we use to
475  * support nested remotes (i.e. a bundle running on a remote node).
476  */
477  connect_name = (replica->ipaddr? replica->ipaddr : "#uname");
478 
479  if (data->control_port == NULL) {
480  port_s = pcmk__itoa(DEFAULT_REMOTE_PORT);
481  }
482 
483  /* This sets replica->container as replica->remote's container, which is
484  * similar to what happens with guest nodes. This is how the scheduler
485  * knows that the bundle node is fenced by recovering the container, and
486  * that remote should be ordered relative to the container.
487  */
488  xml_remote = pe_create_remote_xml(NULL, id, replica->container->id,
489  NULL, NULL, NULL,
490  connect_name, (data->control_port?
491  data->control_port : port_s));
492  free(port_s);
493 
494  /* Abandon our created ID, and pull the copy from the XML, because we
495  * need something that will get freed during data set cleanup to use as
496  * the node ID and uname.
497  */
498  free(id);
499  id = NULL;
500  uname = ID(xml_remote);
501 
502  /* Ensure a node has been created for the guest (it may have already
503  * been, if it has a permanent node attribute), and ensure its weight is
504  * -INFINITY so no other resources can run on it.
505  */
506  node = pe_find_node(parent->cluster->nodes, uname);
507  if (node == NULL) {
508  node = pe_create_node(uname, uname, "remote", "-INFINITY",
509  parent->cluster);
510  } else {
511  node->weight = -INFINITY;
512  }
514 
515  /* unpack_remote_nodes() ensures that each remote node and guest node
516  * has a pe_node_t entry. Ideally, it would do the same for bundle nodes.
517  * Unfortunately, a bundle has to be mostly unpacked before it's obvious
518  * what nodes will be needed, so we do it just above.
519  *
520  * Worse, that means that the node may have been utilized while
521  * unpacking other resources, without our weight correction. The most
522  * likely place for this to happen is when pe__unpack_resource() calls
523  * resource_location() to set a default score in symmetric clusters.
524  * This adds a node *copy* to each resource's allowed nodes, and these
525  * copies will have the wrong weight.
526  *
527  * As a hacky workaround, fix those copies here.
528  *
529  * @TODO Possible alternative: ensure bundles are unpacked before other
530  * resources, so the weight is correct before any copies are made.
531  */
532  g_list_foreach(parent->cluster->resources, (GFunc) disallow_node,
533  (gpointer) uname);
534 
535  replica->node = pe__copy_node(node);
536  replica->node->weight = 500;
537  replica->node->rsc_discover_mode = pe_discover_exclusive;
538 
539  /* Ensure the node shows up as allowed and with the correct discovery set */
540  if (replica->child->allowed_nodes != NULL) {
541  g_hash_table_destroy(replica->child->allowed_nodes);
542  }
543  replica->child->allowed_nodes = pcmk__strkey_table(NULL, free);
544  g_hash_table_insert(replica->child->allowed_nodes,
545  (gpointer) replica->node->details->id,
546  pe__copy_node(replica->node));
547 
548  {
549  pe_node_t *copy = pe__copy_node(replica->node);
550  copy->weight = -INFINITY;
551  g_hash_table_insert(replica->child->parent->allowed_nodes,
552  (gpointer) replica->node->details->id, copy);
553  }
554  if (pe__unpack_resource(xml_remote, &replica->remote, parent,
555  parent->cluster) != pcmk_rc_ok) {
556  return pcmk_rc_unpack_error;
557  }
558 
559  g_hash_table_iter_init(&gIter, replica->remote->allowed_nodes);
560  while (g_hash_table_iter_next(&gIter, NULL, (void **)&node)) {
561  if (pe__is_guest_or_remote_node(node)) {
562  /* Remote resources can only run on 'normal' cluster node */
563  node->weight = -INFINITY;
564  }
565  }
566 
567  replica->node->details->remote_rsc = replica->remote;
568 
569  // Ensure pe__is_guest_node() functions correctly immediately
570  replica->remote->container = replica->container;
571 
572  /* A bundle's #kind is closer to "container" (guest node) than the
573  * "remote" set by pe_create_node().
574  */
575  g_hash_table_insert(replica->node->details->attrs,
576  strdup(CRM_ATTR_KIND), strdup("container"));
577 
578  /* One effect of this is that setup_container() will add
579  * replica->remote to replica->container's fillers, which will make
580  * pe__resource_contains_guest_node() true for replica->container.
581  *
582  * replica->child does NOT get added to replica->container's fillers.
583  * The only noticeable effect if it did would be for its fail count to
584  * be taken into account when checking replica->container's migration
585  * threshold.
586  */
587  parent->children = g_list_append(parent->children, replica->remote);
588  }
589  return pcmk_rc_ok;
590 }
591 
592 static int
593 create_replica_resources(pe_resource_t *parent, pe__bundle_variant_data_t *data,
594  pe__bundle_replica_t *replica)
595 {
596  int rc = pcmk_rc_ok;
597 
598  rc = create_container_resource(parent, data, replica);
599  if (rc != pcmk_rc_ok) {
600  return rc;
601  }
602 
603  rc = create_ip_resource(parent, data, replica);
604  if (rc != pcmk_rc_ok) {
605  return rc;
606  }
607 
608  rc = create_remote_resource(parent, data, replica);
609  if (rc != pcmk_rc_ok) {
610  return rc;
611  }
612 
613  if ((replica->child != NULL) && (replica->ipaddr != NULL)) {
614  add_hash_param(replica->child->meta, "external-ip", replica->ipaddr);
615  }
616 
617  if (replica->remote != NULL) {
618  /*
619  * Allow the remote connection resource to be allocated to a
620  * different node than the one on which the container is active.
621  *
622  * This makes it possible to have Pacemaker Remote nodes running
623  * containers with pacemaker-remoted inside in order to start
624  * services inside those containers.
625  */
627  }
628  return rc;
629 }
630 
631 static void
632 mount_add(pe__bundle_variant_data_t *bundle_data, const char *source,
633  const char *target, const char *options, uint32_t flags)
634 {
635  pe__bundle_mount_t *mount = calloc(1, sizeof(pe__bundle_mount_t));
636 
637  CRM_ASSERT(mount != NULL);
638  mount->source = strdup(source);
639  mount->target = strdup(target);
640  pcmk__str_update(&mount->options, options);
641  mount->flags = flags;
642  bundle_data->mounts = g_list_append(bundle_data->mounts, mount);
643 }
644 
645 static void
646 mount_free(pe__bundle_mount_t *mount)
647 {
648  free(mount->source);
649  free(mount->target);
650  free(mount->options);
651  free(mount);
652 }
653 
654 static void
655 port_free(pe__bundle_port_t *port)
656 {
657  free(port->source);
658  free(port->target);
659  free(port);
660 }
661 
662 static pe__bundle_replica_t *
663 replica_for_remote(pe_resource_t *remote)
664 {
665  pe_resource_t *top = remote;
666  pe__bundle_variant_data_t *bundle_data = NULL;
667 
668  if (top == NULL) {
669  return NULL;
670  }
671 
672  while (top->parent != NULL) {
673  top = top->parent;
674  }
675 
676  get_bundle_variant_data(bundle_data, top);
677  for (GList *gIter = bundle_data->replicas; gIter != NULL;
678  gIter = gIter->next) {
679  pe__bundle_replica_t *replica = gIter->data;
680 
681  if (replica->remote == remote) {
682  return replica;
683  }
684  }
685  CRM_LOG_ASSERT(FALSE);
686  return NULL;
687 }
688 
689 bool
691 {
692  const char *value;
693  GHashTable *params = NULL;
694 
695  if (rsc == NULL) {
696  return false;
697  }
698 
699  // Use NULL node since pcmk__bundle_expand() uses that to set value
700  params = pe_rsc_params(rsc, NULL, data_set);
701  value = g_hash_table_lookup(params, XML_RSC_ATTR_REMOTE_RA_ADDR);
702 
703  return pcmk__str_eq(value, "#uname", pcmk__str_casei)
704  && xml_contains_remote_node(rsc->xml);
705 }
706 
707 const char *
709  xmlNode *xml, const char *field)
710 {
711  // REMOTE_CONTAINER_HACK: Allow remote nodes that start containers with pacemaker remote inside
712 
713  pe_node_t *node = NULL;
714  pe__bundle_replica_t *replica = NULL;
715 
717  return NULL;
718  }
719 
720  replica = replica_for_remote(rsc);
721  if (replica == NULL) {
722  return NULL;
723  }
724 
725  node = replica->container->allocated_to;
726  if (node == NULL) {
727  /* If it won't be running anywhere after the
728  * transition, go with where it's running now.
729  */
730  node = pe__current_node(replica->container);
731  }
732 
733  if(node == NULL) {
734  crm_trace("Cannot determine address for bundle connection %s", rsc->id);
735  return NULL;
736  }
737 
738  crm_trace("Setting address for bundle connection %s to bundle host %s",
739  rsc->id, pe__node_name(node));
740  if(xml != NULL && field != NULL) {
741  crm_xml_add(xml, field, node->details->uname);
742  }
743 
744  return node->details->uname;
745 }
746 
747 #define pe__set_bundle_mount_flags(mount_xml, flags, flags_to_set) do { \
748  flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, \
749  "Bundle mount", ID(mount_xml), flags, \
750  (flags_to_set), #flags_to_set); \
751  } while (0)
752 
753 gboolean
755 {
756  const char *value = NULL;
757  xmlNode *xml_obj = NULL;
758  xmlNode *xml_resource = NULL;
759  pe__bundle_variant_data_t *bundle_data = NULL;
760  bool need_log_mount = TRUE;
761 
762  CRM_ASSERT(rsc != NULL);
763  pe_rsc_trace(rsc, "Processing resource %s...", rsc->id);
764 
765  bundle_data = calloc(1, sizeof(pe__bundle_variant_data_t));
766  rsc->variant_opaque = bundle_data;
767  bundle_data->prefix = strdup(rsc->id);
768 
769  xml_obj = first_named_child(rsc->xml, PE__CONTAINER_AGENT_DOCKER_S);
770  if (xml_obj != NULL) {
771  bundle_data->agent_type = PE__CONTAINER_AGENT_DOCKER;
772  } else {
773  xml_obj = first_named_child(rsc->xml, PE__CONTAINER_AGENT_RKT_S);
774  if (xml_obj != NULL) {
775  bundle_data->agent_type = PE__CONTAINER_AGENT_RKT;
776  } else {
777  xml_obj = first_named_child(rsc->xml, PE__CONTAINER_AGENT_PODMAN_S);
778  if (xml_obj != NULL) {
779  bundle_data->agent_type = PE__CONTAINER_AGENT_PODMAN;
780  } else {
781  return FALSE;
782  }
783  }
784  }
785 
786  // Use 0 for default, minimum, and invalid promoted-max
788  if (value == NULL) {
789  // @COMPAT deprecated since 2.0.0
790  value = crm_element_value(xml_obj, "masters");
791  }
792  pcmk__scan_min_int(value, &bundle_data->promoted_max, 0);
793 
794  // Default replicas to promoted-max if it was specified and 1 otherwise
795  value = crm_element_value(xml_obj, "replicas");
796  if ((value == NULL) && (bundle_data->promoted_max > 0)) {
797  bundle_data->nreplicas = bundle_data->promoted_max;
798  } else {
799  pcmk__scan_min_int(value, &bundle_data->nreplicas, 1);
800  }
801 
802  /*
803  * Communication between containers on the same host via the
804  * floating IPs only works if the container is started with:
805  * --userland-proxy=false --ip-masq=false
806  */
807  value = crm_element_value(xml_obj, "replicas-per-host");
808  pcmk__scan_min_int(value, &bundle_data->nreplicas_per_host, 1);
809  if (bundle_data->nreplicas_per_host == 1) {
811  }
812 
813  bundle_data->container_command = crm_element_value_copy(xml_obj, "run-command");
814  bundle_data->launcher_options = crm_element_value_copy(xml_obj, "options");
815  bundle_data->image = crm_element_value_copy(xml_obj, "image");
816  bundle_data->container_network = crm_element_value_copy(xml_obj, "network");
817 
818  xml_obj = first_named_child(rsc->xml, "network");
819  if(xml_obj) {
820 
821  bundle_data->ip_range_start = crm_element_value_copy(xml_obj, "ip-range-start");
822  bundle_data->host_netmask = crm_element_value_copy(xml_obj, "host-netmask");
823  bundle_data->host_network = crm_element_value_copy(xml_obj, "host-interface");
824  bundle_data->control_port = crm_element_value_copy(xml_obj, "control-port");
825  value = crm_element_value(xml_obj, "add-host");
826  if (crm_str_to_boolean(value, &bundle_data->add_host) != 1) {
827  bundle_data->add_host = TRUE;
828  }
829 
830  for (xmlNode *xml_child = pcmk__xe_first_child(xml_obj); xml_child != NULL;
831  xml_child = pcmk__xe_next(xml_child)) {
832 
833  pe__bundle_port_t *port = calloc(1, sizeof(pe__bundle_port_t));
834  port->source = crm_element_value_copy(xml_child, "port");
835 
836  if(port->source == NULL) {
837  port->source = crm_element_value_copy(xml_child, "range");
838  } else {
839  port->target = crm_element_value_copy(xml_child, "internal-port");
840  }
841 
842  if(port->source != NULL && strlen(port->source) > 0) {
843  if(port->target == NULL) {
844  port->target = strdup(port->source);
845  }
846  bundle_data->ports = g_list_append(bundle_data->ports, port);
847 
848  } else {
849  pe_err("Invalid port directive %s", ID(xml_child));
850  port_free(port);
851  }
852  }
853  }
854 
855  xml_obj = first_named_child(rsc->xml, "storage");
856  for (xmlNode *xml_child = pcmk__xe_first_child(xml_obj); xml_child != NULL;
857  xml_child = pcmk__xe_next(xml_child)) {
858 
859  const char *source = crm_element_value(xml_child, "source-dir");
860  const char *target = crm_element_value(xml_child, "target-dir");
861  const char *options = crm_element_value(xml_child, "options");
862  int flags = pe__bundle_mount_none;
863 
864  if (source == NULL) {
865  source = crm_element_value(xml_child, "source-dir-root");
867  pe__bundle_mount_subdir);
868  }
869 
870  if (source && target) {
871  mount_add(bundle_data, source, target, options, flags);
872  if (strcmp(target, "/var/log") == 0) {
873  need_log_mount = FALSE;
874  }
875  } else {
876  pe_err("Invalid mount directive %s", ID(xml_child));
877  }
878  }
879 
880  xml_obj = first_named_child(rsc->xml, "primitive");
881  if (xml_obj && valid_network(bundle_data)) {
882  char *value = NULL;
883  xmlNode *xml_set = NULL;
884 
885  xml_resource = create_xml_node(NULL, XML_CIB_TAG_INCARNATION);
886 
887  /* @COMPAT We no longer use the <master> tag, but we need to keep it as
888  * part of the resource name, so that bundles don't restart in a rolling
889  * upgrade. (It also avoids needing to change regression tests.)
890  */
891  crm_xml_set_id(xml_resource, "%s-%s", bundle_data->prefix,
892  (bundle_data->promoted_max? "master"
893  : (const char *)xml_resource->name));
894 
895  xml_set = create_xml_node(xml_resource, XML_TAG_META_SETS);
896  crm_xml_set_id(xml_set, "%s-%s-meta", bundle_data->prefix, xml_resource->name);
897 
898  crm_create_nvpair_xml(xml_set, NULL,
900 
901  value = pcmk__itoa(bundle_data->nreplicas);
902  crm_create_nvpair_xml(xml_set, NULL,
904  free(value);
905 
906  value = pcmk__itoa(bundle_data->nreplicas_per_host);
907  crm_create_nvpair_xml(xml_set, NULL,
909  free(value);
910 
912  pcmk__btoa(bundle_data->nreplicas_per_host > 1));
913 
914  if (bundle_data->promoted_max) {
915  crm_create_nvpair_xml(xml_set, NULL,
917 
918  value = pcmk__itoa(bundle_data->promoted_max);
919  crm_create_nvpair_xml(xml_set, NULL,
921  free(value);
922  }
923 
924  //crm_xml_add(xml_obj, XML_ATTR_ID, bundle_data->prefix);
925  add_node_copy(xml_resource, xml_obj);
926 
927  } else if(xml_obj) {
928  pe_err("Cannot control %s inside %s without either ip-range-start or control-port",
929  rsc->id, ID(xml_obj));
930  return FALSE;
931  }
932 
933  if(xml_resource) {
934  int lpc = 0;
935  GList *childIter = NULL;
936  pe__bundle_port_t *port = NULL;
937  GString *buffer = NULL;
938 
939  if (pe__unpack_resource(xml_resource, &(bundle_data->child), rsc,
940  data_set) != pcmk_rc_ok) {
941  return FALSE;
942  }
943 
944  /* Currently, we always map the default authentication key location
945  * into the same location inside the container.
946  *
947  * Ideally, we would respect the host's PCMK_authkey_location, but:
948  * - it may be different on different nodes;
949  * - the actual connection will do extra checking to make sure the key
950  * file exists and is readable, that we can't do here on the DC
951  * - tools such as crm_resource and crm_simulate may not have the same
952  * environment variables as the cluster, causing operation digests to
953  * differ
954  *
955  * Always using the default location inside the container is fine,
956  * because we control the pacemaker_remote environment, and it avoids
957  * having to pass another environment variable to the container.
958  *
959  * @TODO A better solution may be to have only pacemaker_remote use the
960  * environment variable, and have the cluster nodes use a new
961  * cluster option for key location. This would introduce the limitation
962  * of the location being the same on all cluster nodes, but that's
963  * reasonable.
964  */
965  mount_add(bundle_data, DEFAULT_REMOTE_KEY_LOCATION,
966  DEFAULT_REMOTE_KEY_LOCATION, NULL, pe__bundle_mount_none);
967 
968  if (need_log_mount) {
969  mount_add(bundle_data, CRM_BUNDLE_DIR, "/var/log", NULL,
970  pe__bundle_mount_subdir);
971  }
972 
973  port = calloc(1, sizeof(pe__bundle_port_t));
974  if(bundle_data->control_port) {
975  port->source = strdup(bundle_data->control_port);
976  } else {
977  /* If we wanted to respect PCMK_remote_port, we could use
978  * crm_default_remote_port() here and elsewhere in this file instead
979  * of DEFAULT_REMOTE_PORT.
980  *
981  * However, it gains nothing, since we control both the container
982  * environment and the connection resource parameters, and the user
983  * can use a different port if desired by setting control-port.
984  */
985  port->source = pcmk__itoa(DEFAULT_REMOTE_PORT);
986  }
987  port->target = strdup(port->source);
988  bundle_data->ports = g_list_append(bundle_data->ports, port);
989 
990  buffer = g_string_sized_new(1024);
991  for (childIter = bundle_data->child->children; childIter != NULL;
992  childIter = childIter->next) {
993 
994  pe__bundle_replica_t *replica = calloc(1, sizeof(pe__bundle_replica_t));
995 
996  replica->child = childIter->data;
997  replica->child->exclusive_discover = TRUE;
998  replica->offset = lpc++;
999 
1000  // Ensure the child's notify gets set based on the underlying primitive's value
1001  if (pcmk_is_set(replica->child->flags, pe_rsc_notify)) {
1002  pe__set_resource_flags(bundle_data->child, pe_rsc_notify);
1003  }
1004 
1005  allocate_ip(bundle_data, replica, buffer);
1006  bundle_data->replicas = g_list_append(bundle_data->replicas,
1007  replica);
1008  bundle_data->attribute_target = g_hash_table_lookup(replica->child->meta,
1010  }
1011  bundle_data->container_host_options = g_string_free(buffer, FALSE);
1012 
1013  if (bundle_data->attribute_target) {
1014  g_hash_table_replace(rsc->meta, strdup(XML_RSC_ATTR_TARGET),
1015  strdup(bundle_data->attribute_target));
1016  g_hash_table_replace(bundle_data->child->meta,
1017  strdup(XML_RSC_ATTR_TARGET),
1018  strdup(bundle_data->attribute_target));
1019  }
1020 
1021  } else {
1022  // Just a naked container, no pacemaker-remote
1023  GString *buffer = g_string_sized_new(1024);
1024 
1025  for (int lpc = 0; lpc < bundle_data->nreplicas; lpc++) {
1026  pe__bundle_replica_t *replica = calloc(1, sizeof(pe__bundle_replica_t));
1027 
1028  replica->offset = lpc;
1029  allocate_ip(bundle_data, replica, buffer);
1030  bundle_data->replicas = g_list_append(bundle_data->replicas,
1031  replica);
1032  }
1033  bundle_data->container_host_options = g_string_free(buffer, FALSE);
1034  }
1035 
1036  for (GList *gIter = bundle_data->replicas; gIter != NULL;
1037  gIter = gIter->next) {
1038  pe__bundle_replica_t *replica = gIter->data;
1039 
1040  if (create_replica_resources(rsc, bundle_data, replica) != pcmk_rc_ok) {
1041  pe_err("Failed unpacking resource %s", rsc->id);
1042  rsc->fns->free(rsc);
1043  return FALSE;
1044  }
1045 
1046  /* Utilization needs special handling for bundles. It makes no sense for
1047  * the inner primitive to have utilization, because it is tied
1048  * one-to-one to the guest node created by the container resource -- and
1049  * there's no way to set capacities for that guest node anyway.
1050  *
1051  * What the user really wants is to configure utilization for the
1052  * container. However, the schema only allows utilization for
1053  * primitives, and the container resource is implicit anyway, so the
1054  * user can *only* configure utilization for the inner primitive. If
1055  * they do, move the primitive's utilization values to the container.
1056  *
1057  * @TODO This means that bundles without an inner primitive can't have
1058  * utilization. An alternative might be to allow utilization values in
1059  * the top-level bundle XML in the schema, and copy those to each
1060  * container.
1061  */
1062  if (replica->child != NULL) {
1063  GHashTable *empty = replica->container->utilization;
1064 
1065  replica->container->utilization = replica->child->utilization;
1066  replica->child->utilization = empty;
1067  }
1068  }
1069 
1070  if (bundle_data->child) {
1071  rsc->children = g_list_append(rsc->children, bundle_data->child);
1072  }
1073  return TRUE;
1074 }
1075 
1076 static int
1077 replica_resource_active(pe_resource_t *rsc, gboolean all)
1078 {
1079  if (rsc) {
1080  gboolean child_active = rsc->fns->active(rsc, all);
1081 
1082  if (child_active && !all) {
1083  return TRUE;
1084  } else if (!child_active && all) {
1085  return FALSE;
1086  }
1087  }
1088  return -1;
1089 }
1090 
1091 gboolean
1093 {
1094  pe__bundle_variant_data_t *bundle_data = NULL;
1095  GList *iter = NULL;
1096 
1097  get_bundle_variant_data(bundle_data, rsc);
1098  for (iter = bundle_data->replicas; iter != NULL; iter = iter->next) {
1099  pe__bundle_replica_t *replica = iter->data;
1100  int rsc_active;
1101 
1102  rsc_active = replica_resource_active(replica->ip, all);
1103  if (rsc_active >= 0) {
1104  return (gboolean) rsc_active;
1105  }
1106 
1107  rsc_active = replica_resource_active(replica->child, all);
1108  if (rsc_active >= 0) {
1109  return (gboolean) rsc_active;
1110  }
1111 
1112  rsc_active = replica_resource_active(replica->container, all);
1113  if (rsc_active >= 0) {
1114  return (gboolean) rsc_active;
1115  }
1116 
1117  rsc_active = replica_resource_active(replica->remote, all);
1118  if (rsc_active >= 0) {
1119  return (gboolean) rsc_active;
1120  }
1121  }
1122 
1123  /* If "all" is TRUE, we've already checked that no resources were inactive,
1124  * so return TRUE; if "all" is FALSE, we didn't find any active resources,
1125  * so return FALSE.
1126  */
1127  return all;
1128 }
1129 
1139 pe_resource_t *
1141 {
1142  pe__bundle_variant_data_t *bundle_data = NULL;
1143  CRM_ASSERT(bundle && node);
1144 
1145  get_bundle_variant_data(bundle_data, bundle);
1146  for (GList *gIter = bundle_data->replicas; gIter != NULL;
1147  gIter = gIter->next) {
1148  pe__bundle_replica_t *replica = gIter->data;
1149 
1150  CRM_ASSERT(replica && replica->node);
1151  if (replica->node->details == node->details) {
1152  return replica->child;
1153  }
1154  }
1155  return NULL;
1156 }
1157 
1162 static void
1163 print_rsc_in_list(pe_resource_t *rsc, const char *pre_text, long options,
1164  void *print_data)
1165 {
1166  if (rsc != NULL) {
1167  if (options & pe_print_html) {
1168  status_print("<li>");
1169  }
1170  rsc->fns->print(rsc, pre_text, options, print_data);
1171  if (options & pe_print_html) {
1172  status_print("</li>\n");
1173  }
1174  }
1175 }
1176 
1181 static void
1182 bundle_print_xml(pe_resource_t *rsc, const char *pre_text, long options,
1183  void *print_data)
1184 {
1185  pe__bundle_variant_data_t *bundle_data = NULL;
1186  char *child_text = NULL;
1187  CRM_CHECK(rsc != NULL, return);
1188 
1189  if (pre_text == NULL) {
1190  pre_text = "";
1191  }
1192  child_text = crm_strdup_printf("%s ", pre_text);
1193 
1194  get_bundle_variant_data(bundle_data, rsc);
1195 
1196  status_print("%s<bundle ", pre_text);
1197  status_print("id=\"%s\" ", rsc->id);
1198  status_print("type=\"%s\" ", container_agent_str(bundle_data->agent_type));
1199  status_print("image=\"%s\" ", bundle_data->image);
1200  status_print("unique=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_unique));
1201  status_print("managed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_managed));
1202  status_print("failed=\"%s\" ", pe__rsc_bool_str(rsc, pe_rsc_failed));
1203  status_print(">\n");
1204 
1205  for (GList *gIter = bundle_data->replicas; gIter != NULL;
1206  gIter = gIter->next) {
1207  pe__bundle_replica_t *replica = gIter->data;
1208 
1209  CRM_ASSERT(replica);
1210  status_print("%s <replica id=\"%d\">\n", pre_text, replica->offset);
1211  print_rsc_in_list(replica->ip, child_text, options, print_data);
1212  print_rsc_in_list(replica->child, child_text, options, print_data);
1213  print_rsc_in_list(replica->container, child_text, options, print_data);
1214  print_rsc_in_list(replica->remote, child_text, options, print_data);
1215  status_print("%s </replica>\n", pre_text);
1216  }
1217  status_print("%s</bundle>\n", pre_text);
1218  free(child_text);
1219 }
1220 
1221 PCMK__OUTPUT_ARGS("bundle", "uint32_t", "pe_resource_t *", "GList *", "GList *")
1222 int
1223 pe__bundle_xml(pcmk__output_t *out, va_list args)
1224 {
1225  uint32_t show_opts = va_arg(args, uint32_t);
1226  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
1227  GList *only_node = va_arg(args, GList *);
1228  GList *only_rsc = va_arg(args, GList *);
1229 
1230  pe__bundle_variant_data_t *bundle_data = NULL;
1231  int rc = pcmk_rc_no_output;
1232  gboolean printed_header = FALSE;
1233  gboolean print_everything = TRUE;
1234 
1235  CRM_ASSERT(rsc != NULL);
1236 
1237  get_bundle_variant_data(bundle_data, rsc);
1238 
1239  if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
1240  return rc;
1241  }
1242 
1243  print_everything = pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches);
1244 
1245  for (GList *gIter = bundle_data->replicas; gIter != NULL;
1246  gIter = gIter->next) {
1247  pe__bundle_replica_t *replica = gIter->data;
1248  char *id = NULL;
1249  gboolean print_ip, print_child, print_ctnr, print_remote;
1250 
1251  CRM_ASSERT(replica);
1252 
1253  if (pcmk__rsc_filtered_by_node(replica->container, only_node)) {
1254  continue;
1255  }
1256 
1257  print_ip = replica->ip != NULL &&
1258  !replica->ip->fns->is_filtered(replica->ip, only_rsc, print_everything);
1259  print_child = replica->child != NULL &&
1260  !replica->child->fns->is_filtered(replica->child, only_rsc, print_everything);
1261  print_ctnr = !replica->container->fns->is_filtered(replica->container, only_rsc, print_everything);
1262  print_remote = replica->remote != NULL &&
1263  !replica->remote->fns->is_filtered(replica->remote, only_rsc, print_everything);
1264 
1265  if (!print_everything && !print_ip && !print_child && !print_ctnr && !print_remote) {
1266  continue;
1267  }
1268 
1269  if (!printed_header) {
1270  printed_header = TRUE;
1271 
1272  rc = pe__name_and_nvpairs_xml(out, true, "bundle", 6,
1273  "id", rsc->id,
1274  "type", container_agent_str(bundle_data->agent_type),
1275  "image", bundle_data->image,
1276  "unique", pe__rsc_bool_str(rsc, pe_rsc_unique),
1277  "managed", pe__rsc_bool_str(rsc, pe_rsc_managed),
1278  "failed", pe__rsc_bool_str(rsc, pe_rsc_failed));
1279  CRM_ASSERT(rc == pcmk_rc_ok);
1280  }
1281 
1282  id = pcmk__itoa(replica->offset);
1283  rc = pe__name_and_nvpairs_xml(out, true, "replica", 1, "id", id);
1284  free(id);
1285  CRM_ASSERT(rc == pcmk_rc_ok);
1286 
1287  if (print_ip) {
1288  out->message(out, crm_map_element_name(replica->ip->xml), show_opts,
1289  replica->ip, only_node, only_rsc);
1290  }
1291 
1292  if (print_child) {
1293  out->message(out, crm_map_element_name(replica->child->xml), show_opts,
1294  replica->child, only_node, only_rsc);
1295  }
1296 
1297  if (print_ctnr) {
1298  out->message(out, crm_map_element_name(replica->container->xml), show_opts,
1299  replica->container, only_node, only_rsc);
1300  }
1301 
1302  if (print_remote) {
1303  out->message(out, crm_map_element_name(replica->remote->xml), show_opts,
1304  replica->remote, only_node, only_rsc);
1305  }
1306 
1307  pcmk__output_xml_pop_parent(out); // replica
1308  }
1309 
1310  if (printed_header) {
1311  pcmk__output_xml_pop_parent(out); // bundle
1312  }
1313 
1314  return rc;
1315 }
1316 
1317 static void
1318 pe__bundle_replica_output_html(pcmk__output_t *out, pe__bundle_replica_t *replica,
1319  pe_node_t *node, uint32_t show_opts)
1320 {
1321  pe_resource_t *rsc = replica->child;
1322 
1323  int offset = 0;
1324  char buffer[LINE_MAX];
1325 
1326  if(rsc == NULL) {
1327  rsc = replica->container;
1328  }
1329 
1330  if (replica->remote) {
1331  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
1332  rsc_printable_id(replica->remote));
1333  } else {
1334  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
1335  rsc_printable_id(replica->container));
1336  }
1337  if (replica->ipaddr) {
1338  offset += snprintf(buffer + offset, LINE_MAX - offset, " (%s)",
1339  replica->ipaddr);
1340  }
1341 
1342  pe__common_output_html(out, rsc, buffer, node, show_opts);
1343 }
1344 
1345 PCMK__OUTPUT_ARGS("bundle", "uint32_t", "pe_resource_t *", "GList *", "GList *")
1346 int
1347 pe__bundle_html(pcmk__output_t *out, va_list args)
1348 {
1349  uint32_t show_opts = va_arg(args, uint32_t);
1350  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
1351  GList *only_node = va_arg(args, GList *);
1352  GList *only_rsc = va_arg(args, GList *);
1353 
1354  pe__bundle_variant_data_t *bundle_data = NULL;
1355  int rc = pcmk_rc_no_output;
1356  gboolean print_everything = TRUE;
1357 
1358  CRM_ASSERT(rsc != NULL);
1359 
1360  get_bundle_variant_data(bundle_data, rsc);
1361 
1362  if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
1363  return rc;
1364  }
1365 
1366  print_everything = pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches);
1367 
1368  for (GList *gIter = bundle_data->replicas; gIter != NULL;
1369  gIter = gIter->next) {
1370  pe__bundle_replica_t *replica = gIter->data;
1371  gboolean print_ip, print_child, print_ctnr, print_remote;
1372 
1373  CRM_ASSERT(replica);
1374 
1375  if (pcmk__rsc_filtered_by_node(replica->container, only_node)) {
1376  continue;
1377  }
1378 
1379  print_ip = replica->ip != NULL &&
1380  !replica->ip->fns->is_filtered(replica->ip, only_rsc, print_everything);
1381  print_child = replica->child != NULL &&
1382  !replica->child->fns->is_filtered(replica->child, only_rsc, print_everything);
1383  print_ctnr = !replica->container->fns->is_filtered(replica->container, only_rsc, print_everything);
1384  print_remote = replica->remote != NULL &&
1385  !replica->remote->fns->is_filtered(replica->remote, only_rsc, print_everything);
1386 
1387  if (pcmk_is_set(show_opts, pcmk_show_implicit_rscs) ||
1388  (print_everything == FALSE && (print_ip || print_child || print_ctnr || print_remote))) {
1389  /* The text output messages used below require pe_print_implicit to
1390  * be set to do anything.
1391  */
1392  uint32_t new_show_opts = show_opts | pcmk_show_implicit_rscs;
1393 
1394  PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Container bundle%s: %s [%s]%s%s",
1395  (bundle_data->nreplicas > 1)? " set" : "",
1396  rsc->id, bundle_data->image,
1397  pcmk_is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "",
1398  pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)");
1399 
1400  if (pcmk__list_of_multiple(bundle_data->replicas)) {
1401  out->begin_list(out, NULL, NULL, "Replica[%d]", replica->offset);
1402  }
1403 
1404  if (print_ip) {
1405  out->message(out, crm_map_element_name(replica->ip->xml),
1406  new_show_opts, replica->ip, only_node, only_rsc);
1407  }
1408 
1409  if (print_child) {
1410  out->message(out, crm_map_element_name(replica->child->xml),
1411  new_show_opts, replica->child, only_node, only_rsc);
1412  }
1413 
1414  if (print_ctnr) {
1415  out->message(out, crm_map_element_name(replica->container->xml),
1416  new_show_opts, replica->container, only_node, only_rsc);
1417  }
1418 
1419  if (print_remote) {
1420  out->message(out, crm_map_element_name(replica->remote->xml),
1421  new_show_opts, replica->remote, only_node, only_rsc);
1422  }
1423 
1424  if (pcmk__list_of_multiple(bundle_data->replicas)) {
1425  out->end_list(out);
1426  }
1427  } else if (print_everything == FALSE && !(print_ip || print_child || print_ctnr || print_remote)) {
1428  continue;
1429  } else {
1430  PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Container bundle%s: %s [%s]%s%s",
1431  (bundle_data->nreplicas > 1)? " set" : "",
1432  rsc->id, bundle_data->image,
1433  pcmk_is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "",
1434  pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)");
1435 
1436  pe__bundle_replica_output_html(out, replica, pe__current_node(replica->container),
1437  show_opts);
1438  }
1439  }
1440 
1441  PCMK__OUTPUT_LIST_FOOTER(out, rc);
1442  return rc;
1443 }
1444 
1445 static void
1446 pe__bundle_replica_output_text(pcmk__output_t *out, pe__bundle_replica_t *replica,
1447  pe_node_t *node, uint32_t show_opts)
1448 {
1449  pe_resource_t *rsc = replica->child;
1450 
1451  int offset = 0;
1452  char buffer[LINE_MAX];
1453 
1454  if(rsc == NULL) {
1455  rsc = replica->container;
1456  }
1457 
1458  if (replica->remote) {
1459  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
1460  rsc_printable_id(replica->remote));
1461  } else {
1462  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
1463  rsc_printable_id(replica->container));
1464  }
1465  if (replica->ipaddr) {
1466  offset += snprintf(buffer + offset, LINE_MAX - offset, " (%s)",
1467  replica->ipaddr);
1468  }
1469 
1470  pe__common_output_text(out, rsc, buffer, node, show_opts);
1471 }
1472 
1473 PCMK__OUTPUT_ARGS("bundle", "uint32_t", "pe_resource_t *", "GList *", "GList *")
1474 int
1475 pe__bundle_text(pcmk__output_t *out, va_list args)
1476 {
1477  uint32_t show_opts = va_arg(args, uint32_t);
1478  pe_resource_t *rsc = va_arg(args, pe_resource_t *);
1479  GList *only_node = va_arg(args, GList *);
1480  GList *only_rsc = va_arg(args, GList *);
1481 
1482  pe__bundle_variant_data_t *bundle_data = NULL;
1483  int rc = pcmk_rc_no_output;
1484  gboolean print_everything = TRUE;
1485 
1486  get_bundle_variant_data(bundle_data, rsc);
1487 
1488  CRM_ASSERT(rsc != NULL);
1489 
1490  if (rsc->fns->is_filtered(rsc, only_rsc, TRUE)) {
1491  return rc;
1492  }
1493 
1494  print_everything = pcmk__str_in_list(rsc->id, only_rsc, pcmk__str_star_matches);
1495 
1496  for (GList *gIter = bundle_data->replicas; gIter != NULL;
1497  gIter = gIter->next) {
1498  pe__bundle_replica_t *replica = gIter->data;
1499  gboolean print_ip, print_child, print_ctnr, print_remote;
1500 
1501  CRM_ASSERT(replica);
1502 
1503  if (pcmk__rsc_filtered_by_node(replica->container, only_node)) {
1504  continue;
1505  }
1506 
1507  print_ip = replica->ip != NULL &&
1508  !replica->ip->fns->is_filtered(replica->ip, only_rsc, print_everything);
1509  print_child = replica->child != NULL &&
1510  !replica->child->fns->is_filtered(replica->child, only_rsc, print_everything);
1511  print_ctnr = !replica->container->fns->is_filtered(replica->container, only_rsc, print_everything);
1512  print_remote = replica->remote != NULL &&
1513  !replica->remote->fns->is_filtered(replica->remote, only_rsc, print_everything);
1514 
1515  if (pcmk_is_set(show_opts, pcmk_show_implicit_rscs) ||
1516  (print_everything == FALSE && (print_ip || print_child || print_ctnr || print_remote))) {
1517  /* The text output messages used below require pe_print_implicit to
1518  * be set to do anything.
1519  */
1520  uint32_t new_show_opts = show_opts | pcmk_show_implicit_rscs;
1521 
1522  PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Container bundle%s: %s [%s]%s%s",
1523  (bundle_data->nreplicas > 1)? " set" : "",
1524  rsc->id, bundle_data->image,
1525  pcmk_is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "",
1526  pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)");
1527 
1528  if (pcmk__list_of_multiple(bundle_data->replicas)) {
1529  out->list_item(out, NULL, "Replica[%d]", replica->offset);
1530  }
1531 
1532  out->begin_list(out, NULL, NULL, NULL);
1533 
1534  if (print_ip) {
1535  out->message(out, crm_map_element_name(replica->ip->xml),
1536  new_show_opts, replica->ip, only_node, only_rsc);
1537  }
1538 
1539  if (print_child) {
1540  out->message(out, crm_map_element_name(replica->child->xml),
1541  new_show_opts, replica->child, only_node, only_rsc);
1542  }
1543 
1544  if (print_ctnr) {
1545  out->message(out, crm_map_element_name(replica->container->xml),
1546  new_show_opts, replica->container, only_node, only_rsc);
1547  }
1548 
1549  if (print_remote) {
1550  out->message(out, crm_map_element_name(replica->remote->xml),
1551  new_show_opts, replica->remote, only_node, only_rsc);
1552  }
1553 
1554  out->end_list(out);
1555  } else if (print_everything == FALSE && !(print_ip || print_child || print_ctnr || print_remote)) {
1556  continue;
1557  } else {
1558  PCMK__OUTPUT_LIST_HEADER(out, FALSE, rc, "Container bundle%s: %s [%s]%s%s",
1559  (bundle_data->nreplicas > 1)? " set" : "",
1560  rsc->id, bundle_data->image,
1561  pcmk_is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "",
1562  pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)");
1563 
1564  pe__bundle_replica_output_text(out, replica, pe__current_node(replica->container),
1565  show_opts);
1566  }
1567  }
1568 
1569  PCMK__OUTPUT_LIST_FOOTER(out, rc);
1570  return rc;
1571 }
1572 
1577 static void
1578 print_bundle_replica(pe__bundle_replica_t *replica, const char *pre_text,
1579  long options, void *print_data)
1580 {
1581  pe_node_t *node = NULL;
1582  pe_resource_t *rsc = replica->child;
1583 
1584  int offset = 0;
1585  char buffer[LINE_MAX];
1586 
1587  if(rsc == NULL) {
1588  rsc = replica->container;
1589  }
1590 
1591  if (replica->remote) {
1592  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
1593  rsc_printable_id(replica->remote));
1594  } else {
1595  offset += snprintf(buffer + offset, LINE_MAX - offset, "%s",
1596  rsc_printable_id(replica->container));
1597  }
1598  if (replica->ipaddr) {
1599  offset += snprintf(buffer + offset, LINE_MAX - offset, " (%s)",
1600  replica->ipaddr);
1601  }
1602 
1603  node = pe__current_node(replica->container);
1604  common_print(rsc, pre_text, buffer, node, options, print_data);
1605 }
1606 
1611 void
1612 pe__print_bundle(pe_resource_t *rsc, const char *pre_text, long options,
1613  void *print_data)
1614 {
1615  pe__bundle_variant_data_t *bundle_data = NULL;
1616  char *child_text = NULL;
1617  CRM_CHECK(rsc != NULL, return);
1618 
1619  if (options & pe_print_xml) {
1620  bundle_print_xml(rsc, pre_text, options, print_data);
1621  return;
1622  }
1623 
1624  get_bundle_variant_data(bundle_data, rsc);
1625 
1626  if (pre_text == NULL) {
1627  pre_text = " ";
1628  }
1629 
1630  status_print("%sContainer bundle%s: %s [%s]%s%s\n",
1631  pre_text, ((bundle_data->nreplicas > 1)? " set" : ""),
1632  rsc->id, bundle_data->image,
1633  pcmk_is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "",
1634  pcmk_is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)");
1635  if (options & pe_print_html) {
1636  status_print("<br />\n<ul>\n");
1637  }
1638 
1639 
1640  for (GList *gIter = bundle_data->replicas; gIter != NULL;
1641  gIter = gIter->next) {
1642  pe__bundle_replica_t *replica = gIter->data;
1643 
1644  CRM_ASSERT(replica);
1645  if (options & pe_print_html) {
1646  status_print("<li>");
1647  }
1648 
1649  if (pcmk_is_set(options, pe_print_implicit)) {
1650  child_text = crm_strdup_printf(" %s", pre_text);
1651  if (pcmk__list_of_multiple(bundle_data->replicas)) {
1652  status_print(" %sReplica[%d]\n", pre_text, replica->offset);
1653  }
1654  if (options & pe_print_html) {
1655  status_print("<br />\n<ul>\n");
1656  }
1657  print_rsc_in_list(replica->ip, child_text, options, print_data);
1658  print_rsc_in_list(replica->container, child_text, options, print_data);
1659  print_rsc_in_list(replica->remote, child_text, options, print_data);
1660  print_rsc_in_list(replica->child, child_text, options, print_data);
1661  if (options & pe_print_html) {
1662  status_print("</ul>\n");
1663  }
1664  } else {
1665  child_text = crm_strdup_printf("%s ", pre_text);
1666  print_bundle_replica(replica, child_text, options, print_data);
1667  }
1668  free(child_text);
1669 
1670  if (options & pe_print_html) {
1671  status_print("</li>\n");
1672  }
1673  }
1674  if (options & pe_print_html) {
1675  status_print("</ul>\n");
1676  }
1677 }
1678 
1679 static void
1680 free_bundle_replica(pe__bundle_replica_t *replica)
1681 {
1682  if (replica == NULL) {
1683  return;
1684  }
1685 
1686  if (replica->node) {
1687  free(replica->node);
1688  replica->node = NULL;
1689  }
1690 
1691  if (replica->ip) {
1692  free_xml(replica->ip->xml);
1693  replica->ip->xml = NULL;
1694  replica->ip->fns->free(replica->ip);
1695  replica->ip = NULL;
1696  }
1697  if (replica->container) {
1698  free_xml(replica->container->xml);
1699  replica->container->xml = NULL;
1700  replica->container->fns->free(replica->container);
1701  replica->container = NULL;
1702  }
1703  if (replica->remote) {
1704  free_xml(replica->remote->xml);
1705  replica->remote->xml = NULL;
1706  replica->remote->fns->free(replica->remote);
1707  replica->remote = NULL;
1708  }
1709  free(replica->ipaddr);
1710  free(replica);
1711 }
1712 
1713 void
1715 {
1716  pe__bundle_variant_data_t *bundle_data = NULL;
1717  CRM_CHECK(rsc != NULL, return);
1718 
1719  get_bundle_variant_data(bundle_data, rsc);
1720  pe_rsc_trace(rsc, "Freeing %s", rsc->id);
1721 
1722  free(bundle_data->prefix);
1723  free(bundle_data->image);
1724  free(bundle_data->control_port);
1725  free(bundle_data->host_network);
1726  free(bundle_data->host_netmask);
1727  free(bundle_data->ip_range_start);
1728  free(bundle_data->container_network);
1729  free(bundle_data->launcher_options);
1730  free(bundle_data->container_command);
1731  g_free(bundle_data->container_host_options);
1732 
1733  g_list_free_full(bundle_data->replicas,
1734  (GDestroyNotify) free_bundle_replica);
1735  g_list_free_full(bundle_data->mounts, (GDestroyNotify)mount_free);
1736  g_list_free_full(bundle_data->ports, (GDestroyNotify)port_free);
1737  g_list_free(rsc->children);
1738 
1739  if(bundle_data->child) {
1740  free_xml(bundle_data->child->xml);
1741  bundle_data->child->xml = NULL;
1742  bundle_data->child->fns->free(bundle_data->child);
1743  }
1744  common_free(rsc);
1745 }
1746 
1747 enum rsc_role_e
1748 pe__bundle_resource_state(const pe_resource_t *rsc, gboolean current)
1749 {
1750  enum rsc_role_e container_role = RSC_ROLE_UNKNOWN;
1751  return container_role;
1752 }
1753 
1761 int
1763 {
1764  if ((rsc == NULL) || (rsc->variant != pe_container)) {
1765  return 0;
1766  } else {
1767  pe__bundle_variant_data_t *bundle_data = NULL;
1768 
1769  get_bundle_variant_data(bundle_data, rsc);
1770  return bundle_data->nreplicas;
1771  }
1772 }
1773 
1774 void
1776 {
1777  pe__bundle_variant_data_t *bundle_data = NULL;
1778 
1779  get_bundle_variant_data(bundle_data, rsc);
1780  for (GList *item = bundle_data->replicas; item != NULL; item = item->next) {
1781  pe__bundle_replica_t *replica = item->data;
1782 
1783  if (replica->ip) {
1784  replica->ip->fns->count(replica->ip);
1785  }
1786  if (replica->child) {
1787  replica->child->fns->count(replica->child);
1788  }
1789  if (replica->container) {
1790  replica->container->fns->count(replica->container);
1791  }
1792  if (replica->remote) {
1793  replica->remote->fns->count(replica->remote);
1794  }
1795  }
1796 }
1797 
1798 gboolean
1799 pe__bundle_is_filtered(pe_resource_t *rsc, GList *only_rsc, gboolean check_parent)
1800 {
1801  gboolean passes = FALSE;
1802  pe__bundle_variant_data_t *bundle_data = NULL;
1803 
1805  passes = TRUE;
1806  } else {
1807  get_bundle_variant_data(bundle_data, rsc);
1808 
1809  for (GList *gIter = bundle_data->replicas; gIter != NULL; gIter = gIter->next) {
1810  pe__bundle_replica_t *replica = gIter->data;
1811 
1812  if (replica->ip != NULL && !replica->ip->fns->is_filtered(replica->ip, only_rsc, FALSE)) {
1813  passes = TRUE;
1814  break;
1815  } else if (replica->child != NULL && !replica->child->fns->is_filtered(replica->child, only_rsc, FALSE)) {
1816  passes = TRUE;
1817  break;
1818  } else if (!replica->container->fns->is_filtered(replica->container, only_rsc, FALSE)) {
1819  passes = TRUE;
1820  break;
1821  } else if (replica->remote != NULL && !replica->remote->fns->is_filtered(replica->remote, only_rsc, FALSE)) {
1822  passes = TRUE;
1823  break;
1824  }
1825  }
1826  }
1827 
1828  return !passes;
1829 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
pe_node_t * pe_find_node(GList *node_list, const char *uname)
Definition: status.c:443
xmlNode * crm_create_op_xml(xmlNode *parent, const char *prefix, const char *task, const char *interval_spec, const char *timeout)
Create a CIB XML element for an operation.
Definition: operations.c:474
bool pe__is_guest_or_remote_node(const pe_node_t *node)
Definition: remote.c:41
char data[0]
Definition: cpg.c:55
#define INFINITY
Definition: crm.h:99
int pe__bundle_text(pcmk__output_t *out, va_list args)
Definition: bundle.c:1475
#define CRM_ATTR_KIND
Definition: crm.h:115
Control output from tools.
gboolean pe__bundle_is_filtered(pe_resource_t *rsc, GList *only_rsc, gboolean check_parent)
Definition: bundle.c:1799
int pe__common_output_html(pcmk__output_t *out, pe_resource_t *rsc, const char *name, pe_node_t *node, unsigned int options)
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition: strings.c:127
pe_resource_t * container
Definition: pe_types.h:387
const char * name
Definition: cib.c:24
#define XML_ATTR_TYPE
Definition: msg_xml.h:138
GList * children
Definition: pe_types.h:384
#define XML_BOOLEAN_FALSE
Definition: msg_xml.h:147
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2930
xmlNode * xml
Definition: pe_types.h:331
GHashTable * meta
Definition: pe_types.h:380
#define pe_rsc_unique
Definition: pe_types.h:262
#define pe_rsc_notify
Definition: pe_types.h:261
resource_object_functions_t * fns
Definition: pe_types.h:340
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: nvpair.c:323
pe_node_t * pe__copy_node(const pe_node_t *this_node)
Definition: utils.c:89
void pcmk__add_separated_word(GString **list, size_t init_size, const char *word, const char *separator)
Definition: strings.c:703
#define PCMK_RESOURCE_CLASS_OCF
Definition: agents.h:27
pe_resource_t * pe_find_resource(GList *rsc_list, const char *id_rh)
Definition: status.c:391
#define CRM_LOG_ASSERT(expr)
Definition: logging.h:211
#define pe_rsc_allow_remote_remotes
Definition: pe_types.h:273
#define XML_RSC_ATTR_INCARNATION_MAX
Definition: msg_xml.h:229
#define CRM_BUNDLE_DIR
Definition: config.h:14
#define XML_RSC_ATTR_TARGET
Definition: msg_xml.h:224
enum rsc_role_e pe__bundle_resource_state(const pe_resource_t *rsc, gboolean current)
Definition: bundle.c:1748
#define XML_RSC_ATTR_REMOTE_RA_ADDR
Definition: msg_xml.h:250
void crm_xml_sanitize_id(char *id)
Sanitize a string so it is usable as an XML ID.
Definition: xml.c:1190
#define pe__set_resource_flags(resource, flags_to_set)
Definition: internal.h:74
#define DEFAULT_REMOTE_PORT
Definition: lrmd.h:51
#define DEFAULT_REMOTE_KEY_LOCATION
Definition: lrmd.h:49
int pe__common_output_text(pcmk__output_t *out, pe_resource_t *rsc, const char *name, pe_node_t *node, unsigned int options)
#define XML_TAG_ATTR_SETS
Definition: msg_xml.h:209
#define XML_RSC_ATTR_PROMOTABLE
Definition: msg_xml.h:232
xmlNode * pe_create_remote_xml(xmlNode *parent, const char *uname, const char *container_id, const char *migrateable, const char *is_managed, const char *start_timeout, const char *server, const char *port)
Definition: remote.c:156
bool pe__bundle_needs_remote_name(pe_resource_t *rsc, pe_working_set_t *data_set)
Definition: bundle.c:690
int weight
Definition: pe_types.h:249
void pe__free_bundle(pe_resource_t *rsc)
Definition: bundle.c:1714
#define pe_rsc_failed
Definition: pe_types.h:276
const char * pe__add_bundle_remote_name(pe_resource_t *rsc, pe_working_set_t *data_set, xmlNode *xml, const char *field)
Definition: bundle.c:708
char * crm_element_value_copy(const xmlNode *data, const char *name)
Retrieve a copy of the value of an XML attribute.
Definition: nvpair.c:714
#define XML_ATTR_ID
Definition: msg_xml.h:134
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:517
#define XML_CIB_TAG_RESOURCE
Definition: msg_xml.h:217
#define XML_BOOLEAN_TRUE
Definition: msg_xml.h:146
#define PCMK__OUTPUT_ARGS(ARGS...)
#define CRM_DAEMON_DIR
Definition: config.h:24
int pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name, size_t pairs_count,...)
Definition: pe_output.c:544
#define crm_trace(fmt, args...)
Definition: logging.h:365
void pcmk__g_strcat(GString *buffer,...) G_GNUC_NULL_TERMINATED
Definition: strings.c:1214
bool xml_contains_remote_node(xmlNode *xml)
Definition: remote.c:84
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
xmlNode * add_node_copy(xmlNode *new_parent, xmlNode *xml_node)
Definition: xml.c:727
void crm_xml_set_id(xmlNode *xml, const char *format,...) G_GNUC_PRINTF(2
void pe__count_bundle(pe_resource_t *rsc)
Definition: bundle.c:1775
struct pe_node_shared_s * details
Definition: pe_types.h:252
#define pe__set_bundle_mount_flags(mount_xml, flags, flags_to_set)
Definition: bundle.c:747
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:270
void common_free(pe_resource_t *rsc)
Definition: complex.c:926
unsigned long long flags
Definition: pe_types.h:355
const char * uname
Definition: pe_types.h:216
#define XML_RSC_ATTR_ORDERED
Definition: msg_xml.h:226
pe_working_set_t * data_set
#define XML_TAG_META_SETS
Definition: msg_xml.h:210
void pcmk__str_update(char **str, const char *value)
Definition: strings.c:1190
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition: xml.c:749
void(* print)(pe_resource_t *, const char *, long, void *)
Definition: pe_types.h:52
#define XML_RSC_ATTR_INCARNATION_NODEMAX
Definition: msg_xml.h:231
gboolean pe__bundle_active(pe_resource_t *rsc, gboolean all)
Definition: bundle.c:1092
void(* free)(pe_resource_t *)
Definition: pe_types.h:56
void free_xml(xmlNode *child)
Definition: xml.c:885
enum pe_obj_types variant
Definition: pe_types.h:338
int pe__bundle_xml(pcmk__output_t *out, va_list args)
Definition: bundle.c:1223
void pcmk__output_xml_pop_parent(pcmk__output_t *out)
Definition: output_xml.c:513
int rsc_discover_mode
Definition: pe_types.h:253
void common_print(pe_resource_t *rsc, const char *pre_text, const char *name, pe_node_t *node, long options, void *print_data)
Definition: native.c:771
int pe__bundle_html(pcmk__output_t *out, va_list args)
Definition: bundle.c:1347
int pe_bundle_replicas(const pe_resource_t *rsc)
Get the number of configured replicas in a bundle.
Definition: bundle.c:1762
#define XML_RSC_ATTR_UNIQUE
Definition: msg_xml.h:237
#define PCMK__OUTPUT_LIST_FOOTER(out_obj, retcode)
const char * target
Definition: pcmk_fence.c:29
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:427
#define XML_RSC_ATTR_PROMOTED_MAX
Definition: msg_xml.h:233
#define SBIN_DIR
Definition: config.h:559
#define PCMK__OUTPUT_LIST_HEADER(out_obj, cond, retcode, title...)
Cluster status and scheduling.
gboolean(* is_filtered)(pe_resource_t *, GList *, gboolean)
Definition: pe_types.h:58
bool pcmk__rsc_filtered_by_node(pe_resource_t *rsc, GList *only_node)
Definition: utils.c:768
#define XML_CIB_TAG_INCARNATION
Definition: msg_xml.h:219
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:611
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition: common.c:504
void * variant_opaque
Definition: pe_types.h:339
#define CRM_ASSERT(expr)
Definition: results.h:42
const char * rsc_printable_id(pe_resource_t *rsc)
Definition: utils.c:568
void pe__print_bundle(pe_resource_t *rsc, const char *pre_text, long options, void *print_data)
Definition: bundle.c:1612
#define status_print(fmt, args...)
This structure contains everything that makes up a single output formatter.
GHashTable * pe_rsc_params(pe_resource_t *rsc, const pe_node_t *node, pe_working_set_t *data_set)
Get a table of resource parameters.
Definition: complex.c:429
char uname[MAX_NAME]
Definition: cpg.c:50
#define pe__clear_resource_flags(resource, flags_to_clear)
Definition: internal.h:80
rsc_role_e
Possible roles that a resource can be in.
Definition: common.h:92
pe_node_t * pe_create_node(const char *id, const char *uname, const char *type, const char *score, pe_working_set_t *data_set)
Definition: unpack.c:381
gboolean pe__unpack_bundle(pe_resource_t *rsc, pe_working_set_t *data_set)
Definition: bundle.c:754
#define pe_rsc_trace(rsc, fmt, args...)
Definition: internal.h:47
xmlNode * crm_create_nvpair_xml(xmlNode *parent, const char *id, const char *name, const char *value)
Create an XML name/value pair.
Definition: nvpair.c:833
pe_resource_t * pe__find_bundle_replica(const pe_resource_t *bundle, const pe_node_t *node)
Definition: bundle.c:1140
#define ID(x)
Definition: msg_xml.h:468
#define pe_err(fmt...)
Definition: internal.h:49
const char * parent
Definition: cib.c:25
#define pe_rsc_managed
Definition: pe_types.h:257
uint64_t flags
Definition: remote.c:215
pe_resource_t * parent
Definition: pe_types.h:336
int pe__unpack_resource(xmlNode *xml_obj, pe_resource_t **rsc, pe_resource_t *parent, pe_working_set_t *data_set)
Definition: complex.c:562
gboolean(* active)(pe_resource_t *, gboolean)
Definition: pe_types.h:53
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:269
char * id
Definition: pe_types.h:329
GHashTable * allowed_nodes
Definition: pe_types.h:375
gboolean pcmk__str_in_list(const gchar *s, const GList *lst, uint32_t flags)
Definition: strings.c:883