diff --git a/lib/pengine/container.c b/lib/pengine/container.c index d4ba366265..4b2497ccbf 100644 --- a/lib/pengine/container.c +++ b/lib/pengine/container.c @@ -1,509 +1,491 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #define VARIANT_CONTAINER 1 #include "./variant.h" void tuple_free(container_grouping_t *tuple); static char * next_ip(char *last_ip) { int oct1 = 0; int oct2 = 0; int oct3 = 0; int oct4 = 0; int rc = sscanf(last_ip, "%d.%d.%d.%d", &oct1, &oct2, &oct3, &oct4); if (rc != 4) { return NULL; } else if(oct4 > 255) { return NULL; } return crm_strdup_printf("%d.%d.%d.%d", oct1, oct2, oct3, oct4+1); } static xmlNode * create_resource(const char *name, const char *provider, const char *kind) { xmlNode *rsc = create_xml_node(NULL, XML_CIB_TAG_RESOURCE); crm_xml_add(rsc, XML_ATTR_ID, name); crm_xml_add(rsc, XML_AGENT_ATTR_CLASS, "ocf"); crm_xml_add(rsc, XML_AGENT_ATTR_PROVIDER, provider); crm_xml_add(rsc, "type", kind); return rsc; } static void create_nvp(xmlNode *parent, const char *name, const char *value) { char *id = crm_strdup_printf("%s-%s", ID(parent), name); xmlNode *xml_nvp = create_xml_node(parent, XML_CIB_TAG_NVPAIR); crm_xml_add(xml_nvp, XML_ATTR_ID, id); free(id); crm_xml_add(xml_nvp, XML_NVPAIR_ATTR_NAME, name); crm_xml_add(xml_nvp, XML_NVPAIR_ATTR_VALUE, value); } static void create_op(xmlNode *parent, const char *prefix, const char *task, const char *interval) { char *id = crm_strdup_printf("%s-%s-%s", prefix, task, interval); xmlNode *xml_op = create_xml_node(parent, "op"); crm_xml_add(xml_op, XML_ATTR_ID, id); free(id); crm_xml_add(xml_op, XML_LRM_ATTR_INTERVAL, interval); crm_xml_add(xml_op, "name", task); } static container_grouping_t * create_container( resource_t *parent, container_variant_data_t *data, resource_t *child, int index, pe_working_set_t * data_set) { xmlNode *xml_obj = NULL; container_grouping_t *tuple = calloc(1, sizeof(container_grouping_t)); tuple->offset = index; if(data->ip_range_start) { char *id = NULL; xmlNode *xml_ip = NULL; // Create an IP resource if(data->ip_last) { char *next = next_ip(data->ip_last); free(data->ip_last); data->ip_last = next; } else { data->ip_last = strdup(data->ip_range_start); } id = crm_strdup_printf("%s-ip-%s", data->prefix, data->ip_last); xml_ip = create_resource(id, "heartbeat", "IPaddr2"); id = crm_strdup_printf("%s-attributes-%d", data->prefix, tuple->offset); xml_obj = create_xml_node(xml_ip, XML_TAG_ATTR_SETS); crm_xml_add(xml_obj, XML_ATTR_ID, id); free(id); create_nvp(xml_obj, "ip", data->ip_last); // TODO: Support NIC and/or netmask xml_obj = create_xml_node(xml_ip, "operations"); create_op(xml_obj, ID(xml_ip), "monitor", "60s"); // TODO: Other ops? Timeouts and intervals from underlying resource? if (common_unpack(xml_ip, &tuple->ip, NULL, data_set) == false) { tuple_free(tuple); return NULL; } } // Create a container { int offset = 0, max = 1024; char *buffer = calloc(1, max+1); char *id = crm_strdup_printf("%s-docker-%d", data->prefix, tuple->offset); xmlNode *xml_docker = create_resource(id, "heartbeat", "docker"); id = crm_strdup_printf("%s-attributes-%d", data->prefix, tuple->offset); xml_obj = create_xml_node(xml_docker, XML_TAG_ATTR_SETS); crm_xml_add(xml_obj, XML_ATTR_ID, id); free(id); create_nvp(xml_obj, "image", data->image); create_nvp(xml_obj, "allow_pull", "true"); create_nvp(xml_obj, "force_kill", "false"); create_nvp(xml_obj, "reuse", "false"); offset += snprintf(buffer+offset, max-offset, " -v %s:%s", DEFAULT_REMOTE_KEY_LOCATION, DEFAULT_REMOTE_KEY_LOCATION); offset += snprintf(buffer+offset, max-offset, " -p %s:%d:%d", data->ip_last, DEFAULT_REMOTE_PORT, DEFAULT_REMOTE_PORT); if(data->docker_run_options) { offset += snprintf(buffer+offset, max-offset, " %s", data->docker_run_options); } create_nvp(xml_obj, "run_opts", buffer); free(buffer); if(child) { // TODO: Use autoconf var create_nvp(xml_obj, "run_cmd", "/usr/sbin/pacemaker_remoted"); create_nvp(xml_obj, "monitor_cmd", "/bin/true"); // We just want to know if the container // is alive, we'll monitor the child independantly /* } else if(child && data->isolated) { */ /* create_nvp(xml_obj, "run_cmd", "/usr/libexec/pacemaker/lrmd"); */ /* create_nvp(xml_obj, "monitor_cmd", "/usr/libexec/pacemaker/lrmd_internal_ctl -c poke"); */ } else { // TODO: Leave blank to use the built-in one? } xml_obj = create_xml_node(xml_docker, "operations"); create_op(xml_obj, ID(xml_docker), "monitor", "60s"); // TODO: Other ops? Timeouts and intervals from underlying resource? if (common_unpack(xml_docker, &tuple->docker, NULL, data_set) == false) { tuple_free(tuple); return NULL; } } // Create a remote resource if(data->ip_last && child) { node_t *node = NULL; xmlNode *xml_remote = NULL; - char *id = crm_strdup_printf("%s-remote-%d", data->prefix, tuple->offset); char *nodeid = crm_strdup_printf("%s-%d", data->prefix, tuple->offset); + char *id = strdup(nodeid); if(remote_id_conflict(id, data_set)) { // The biggest hammer we have id = crm_strdup_printf("pcmk-internal-%s-remote-%d", child->id, tuple->offset); } CRM_ASSERT(remote_id_conflict(id, data_set) == FALSE); xml_remote = create_resource(id, "pacemaker", "remote"); xml_obj = create_xml_node(xml_remote, "operations"); create_op(xml_obj, ID(xml_remote), "monitor", "60s"); id = crm_strdup_printf("%s-attributes-%d", data->prefix, tuple->offset); xml_obj = create_xml_node(xml_remote, XML_TAG_ATTR_SETS); crm_xml_add(xml_obj, XML_ATTR_ID, id); free(id); create_nvp(xml_obj, "addr", data->ip_last); create_nvp(xml_obj, "port", crm_itoa(DEFAULT_REMOTE_PORT)); id = crm_strdup_printf("%s-meta-%d", data->prefix, tuple->offset); xml_obj = create_xml_node(xml_remote, XML_TAG_META_SETS); crm_xml_add(xml_obj, XML_ATTR_ID, id); free(id); create_nvp(xml_obj, XML_OP_ATTR_ALLOW_MIGRATE, "false"); // Sets up node->details->remote_rsc->container == tuple->docker create_nvp(xml_obj, XML_RSC_ATTR_CONTAINER, tuple->docker->id); // TODO: Do this generically, eg with rsc->flags // create_nvp(xml_obj, XML_RSC_ATTR_INTERNAL_RSC, "true"); // Suppress printing // tuple->docker->fillers = g_list_append(tuple->docker->fillers, child); // -INFINITY prevents anyone else from running here node = create_node(strdup(nodeid), nodeid, "remote", "-INFINITY", data_set); tuple->node = node_copy(node); tuple->node->weight = 500; nodeid = NULL; id = NULL; if (common_unpack(xml_remote, &tuple->remote, NULL, data_set) == false) { tuple_free(tuple); return NULL; } tuple->node->details->remote_rsc = tuple->remote; } if(child) { - GListPtr list = g_list_append(NULL, tuple->node); - CRM_ASSERT(data->ip_range_start); tuple->child = child; - - if(tuple->child->allowed_nodes) { - g_hash_table_destroy(tuple->child->allowed_nodes); - } - - tuple->child->allowed_nodes = node_hash_from_list(list); - g_list_free(list); - -#if 0 - GHashTableIter iter; - - g_hash_table_iter_init(&iter, tuple->child->allowed_nodes); - while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) { - node->weight = 500; - } -#endif } -#if 1 + if(tuple->ip) { parent->children = g_list_append(parent->children, tuple->ip); } if(tuple->docker) { parent->children = g_list_append(parent->children, tuple->docker); } if(tuple->remote) { parent->children = g_list_append(parent->children, tuple->remote); } -#endif + data->tuples = g_list_append(data->tuples, tuple); return tuple; } gboolean container_unpack(resource_t * rsc, pe_working_set_t * data_set) { xmlNode *xml_resource = NULL; container_variant_data_t *container_data = NULL; pe_rsc_trace(rsc, "Processing resource %s...", rsc->id); container_data = calloc(1, sizeof(container_variant_data_t)); rsc->variant_opaque = container_data; container_data->prefix = strdup(rsc->id); container_data->image = crm_element_value_copy(rsc->xml, "image"); for (xmlNode *xml_child = __xml_first_child_element(rsc->xml); xml_child != NULL; xml_child = __xml_next_element(xml_child)) { if (crm_str_eq((const char *)xml_child->name, "docker", TRUE)) { container_data->xml_docker_options = xml_child; container_data->xml_mounts = first_named_child(xml_child, "storage"); container_data->xml_network = first_named_child(xml_child, "network"); } else if(xml_resource == NULL) { xml_resource = xml_child; } else { pe_err("Only one child (%s) is per container (%s): Ignoring %s", crm_element_value(xml_resource, XML_ATTR_ID), rsc->id, crm_element_value(xml_child, XML_ATTR_ID)); } } if(container_data->xml_docker_options) { const char *replicas = crm_element_value(container_data->xml_docker_options, "replicas"); container_data->replicas = crm_parse_int(replicas, "1"); /* char *docker_options; */ } else { container_data->replicas = 1; } if(container_data->xml_network) { container_data->ip_range_start = crm_element_value_copy(container_data->xml_network, "ip-range-start"); } // TODO: Parse the mount options // TODO: Parse the port options if(xml_resource && container_data->ip_range_start) { int lpc = 0; GListPtr childIter = NULL; resource_t *new_rsc = NULL; // TODO: Enforce that clone-max is >= container_data->replicas if (common_unpack(xml_resource, &new_rsc, rsc, data_set) == FALSE) { pe_err("Failed unpacking resource %s", crm_element_value(rsc->xml, XML_ATTR_ID)); if (new_rsc != NULL && new_rsc->fns != NULL) { new_rsc->fns->free(new_rsc); } return FALSE; } else if(container_data->replicas > 1 && new_rsc->variant < pe_clone) { pe_err("%d replicas requested but %s is not a clone", container_data->replicas, new_rsc->id); // fake a clone?? // container_data->child = new_rsc; return FALSE; } container_data->child = new_rsc; for(childIter = container_data->child->children; childIter != NULL; childIter = childIter->next) { create_container(rsc, container_data, childIter->data, lpc++, data_set); } } else if(xml_resource) { pe_err("Cannot control %s inside container %s without a value for ip-range-start", rsc->id, ID(xml_resource)); return FALSE; } else { // Just a naked container, no pacemaker-remote for(int lpc = 0; lpc < container_data->replicas; lpc++) { create_container(rsc, container_data, NULL, lpc, data_set); } } if(container_data->child) { rsc->children = g_list_append(rsc->children, container_data->child); } return TRUE; } gboolean container_active(resource_t * rsc, gboolean all) { return TRUE; } static void container_print_xml(resource_t * rsc, const char *pre_text, long options, void *print_data) { container_variant_data_t *container_data = NULL; char *child_text = NULL; CRM_CHECK(rsc != NULL, return); if (pre_text == NULL) { pre_text = ""; } child_text = crm_concat(pre_text, " ", ' '); status_print("%sid); status_print("managed=\"%s\" ", is_set(rsc->flags, pe_rsc_managed) ? "true" : "false"); status_print("failed=\"%s\" ", is_set(rsc->flags, pe_rsc_failed) ? "true" : "false"); status_print(">\n"); get_container_variant_data(container_data, rsc); status_print("%sDocker container: %s [%s]%s%s", pre_text, rsc->id, container_data->image, is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "", is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)"); for (GListPtr gIter = container_data->tuples; gIter != NULL; gIter = gIter->next) { container_grouping_t *tuple = (container_grouping_t *)gIter->data; CRM_ASSERT(tuple); if(tuple->ip) { tuple->ip->fns->print(tuple->ip, child_text, options, print_data); } if(tuple->child) { tuple->child->fns->print(tuple->child, child_text, options, print_data); } if(tuple->docker) { tuple->docker->fns->print(tuple->docker, child_text, options, print_data); } if(tuple->remote) { tuple->remote->fns->print(tuple->remote, child_text, options, print_data); } } status_print("%s\n", pre_text); free(child_text); } void container_print(resource_t * rsc, const char *pre_text, long options, void *print_data) { container_variant_data_t *container_data = NULL; char *child_text = NULL; CRM_CHECK(rsc != NULL, return); if (options & pe_print_xml) { container_print_xml(rsc, pre_text, options, print_data); return; } get_container_variant_data(container_data, rsc); if (pre_text == NULL) { pre_text = " "; } child_text = crm_strdup_printf(" %s", pre_text); status_print("%sDocker container%s: %s [%s]%s%s\n", pre_text, container_data->replicas>1?" set":"", rsc->id, container_data->image, is_set(rsc->flags, pe_rsc_unique) ? " (unique)" : "", is_set(rsc->flags, pe_rsc_managed) ? "" : " (unmanaged)"); for (GListPtr gIter = container_data->tuples; gIter != NULL; gIter = gIter->next) { container_grouping_t *tuple = (container_grouping_t *)gIter->data; CRM_ASSERT(tuple); if(g_list_length(container_data->tuples) > 1) { status_print(" %sReplica[%d]\n", pre_text, tuple->offset); } if(tuple->ip) { tuple->ip->fns->print(tuple->ip, child_text, options, print_data); } if(tuple->docker) { tuple->docker->fns->print(tuple->docker, child_text, options, print_data); } if(tuple->remote) { tuple->remote->fns->print(tuple->remote, child_text, options, print_data); } if(tuple->child) { tuple->child->fns->print(tuple->child, child_text, options, print_data); } } } void tuple_free(container_grouping_t *tuple) { if(tuple->ip) { tuple->ip->fns->free(tuple->ip); tuple->ip = NULL; } if(tuple->child) { tuple->child->fns->free(tuple->child); tuple->child = NULL; } if(tuple->docker) { tuple->docker->fns->free(tuple->docker); tuple->docker = NULL; } if(tuple->remote) { tuple->remote->fns->free(tuple->remote); tuple->remote = NULL; } free(tuple); } void container_free(resource_t * rsc) { container_variant_data_t *container_data = NULL; CRM_CHECK(rsc != NULL, return); get_container_variant_data(container_data, rsc); pe_rsc_trace(rsc, "Freeing %s", rsc->id); for (GListPtr gIter = container_data->tuples; gIter != NULL; gIter = gIter->next) { container_grouping_t *tuple = (container_grouping_t *)gIter->data; CRM_ASSERT(tuple); tuple_free(tuple); } common_free(rsc); } enum rsc_role_e container_resource_state(const resource_t * rsc, gboolean current) { enum rsc_role_e container_role = RSC_ROLE_UNKNOWN; return container_role; } diff --git a/pengine/container.c b/pengine/container.c index a7b83a2816..655f488201 100644 --- a/pengine/container.c +++ b/pengine/container.c @@ -1,300 +1,330 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #define VARIANT_CONTAINER 1 #include +static bool +is_child_container_node(container_variant_data_t *data, pe_node_t *node) +{ + for (GListPtr gIter = data->tuples; gIter != NULL; gIter = gIter->next) { + container_grouping_t *tuple = (container_grouping_t *)gIter->data; + if(node->details == tuple->node->details) { + return TRUE; + } + } + return FALSE; +} + node_t * container_color(resource_t * rsc, node_t * prefer, pe_working_set_t * data_set) { container_variant_data_t *container_data = NULL; CRM_CHECK(rsc != NULL, return NULL); get_container_variant_data(container_data, rsc); for (GListPtr gIter = container_data->tuples; gIter != NULL; gIter = gIter->next) { container_grouping_t *tuple = (container_grouping_t *)gIter->data; CRM_ASSERT(tuple); if(tuple->docker) { tuple->docker->cmds->allocate(tuple->docker, prefer, data_set); } if(tuple->ip) { tuple->ip->cmds->allocate(tuple->ip, prefer, data_set); } if(tuple->remote) { tuple->remote->cmds->allocate(tuple->remote, prefer, data_set); } // Explicitly allocate tuple->child before the container->child if(tuple->child) { + pe_node_t *node = NULL; + GHashTableIter iter; + g_hash_table_iter_init(&iter, tuple->child->allowed_nodes); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) { + if(node->details != tuple->node->details) { + node->weight = -INFINITY; + } else { + node->weight = INFINITY; + } + } + set_bit(tuple->child->parent->flags, pe_rsc_allocating); tuple->child->cmds->allocate(tuple->child, tuple->node, data_set); clear_bit(tuple->child->parent->flags, pe_rsc_allocating); } } if(container_data->child) { -// container_data->child->cmds->allocate(container_data->child, prefer, data_set); + pe_node_t *node = NULL; + GHashTableIter iter; + g_hash_table_iter_init(&iter, container_data->child->allowed_nodes); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) { + if(is_child_container_node(container_data, node)) { + node->weight = 0; + } else { + node->weight = -INFINITY; + } + } + container_data->child->cmds->allocate(container_data->child, prefer, data_set); } return NULL; } void container_create_actions(resource_t * rsc, pe_working_set_t * data_set) { container_variant_data_t *container_data = NULL; CRM_CHECK(rsc != NULL, return); get_container_variant_data(container_data, rsc); for (GListPtr gIter = container_data->tuples; gIter != NULL; gIter = gIter->next) { container_grouping_t *tuple = (container_grouping_t *)gIter->data; CRM_ASSERT(tuple); if(tuple->ip) { tuple->ip->cmds->create_actions(tuple->ip, data_set); } if(tuple->docker) { tuple->docker->cmds->create_actions(tuple->docker, data_set); } if(tuple->remote) { tuple->remote->cmds->create_actions(tuple->remote, data_set); } } if(container_data->child) { container_data->child->cmds->create_actions(container_data->child, data_set); } } void container_internal_constraints(resource_t * rsc, pe_working_set_t * data_set) { container_variant_data_t *container_data = NULL; CRM_CHECK(rsc != NULL, return); get_container_variant_data(container_data, rsc); for (GListPtr gIter = container_data->tuples; gIter != NULL; gIter = gIter->next) { char *id = NULL; container_grouping_t *tuple = (container_grouping_t *)gIter->data; CRM_ASSERT(tuple); if(tuple->docker) { - complex_set_cmds(tuple->docker); tuple->docker->cmds->internal_constraints(tuple->docker, data_set); } if(tuple->ip) { - complex_set_cmds(tuple->ip); tuple->ip->cmds->internal_constraints(tuple->ip, data_set); // Start ip then docker new_rsc_order(tuple->ip, RSC_START, tuple->docker, RSC_START, pe_order_runnable_left, data_set); new_rsc_order(tuple->docker, RSC_STOP, tuple->ip, RSC_STOP, pe_order_implies_first, data_set); id = crm_strdup_printf("%s-ip-with-docker-%d", rsc->id, tuple->offset); rsc_colocation_new(id, NULL, INFINITY, tuple->ip, tuple->docker, NULL, NULL, data_set); free(id); } if(tuple->remote) { CRM_ASSERT(tuple->ip); - complex_set_cmds(tuple->remote); tuple->remote->cmds->internal_constraints(tuple->remote, data_set); // Start docker then remote new_rsc_order( tuple->docker, RSC_START, tuple->remote, RSC_START, pe_order_runnable_left, data_set); new_rsc_order( tuple->remote, RSC_STOP, tuple->docker, RSC_STOP, pe_order_implies_first, data_set); id = crm_strdup_printf("%s-remote-with-ip-%d", rsc->id, tuple->offset); rsc_colocation_new(id, NULL, INFINITY, tuple->remote, tuple->ip, NULL, NULL, data_set); free(id); } if(tuple->child) { CRM_ASSERT(tuple->remote); // Start remote then child new_rsc_order( tuple->remote, RSC_START, tuple->child, RSC_START, pe_order_runnable_left, data_set); new_rsc_order( tuple->child, RSC_STOP, tuple->remote, RSC_STOP, pe_order_implies_first, data_set); // TODO: child _in_ remote } } if(container_data->child) { container_data->child->cmds->internal_constraints(container_data->child, data_set); } } void container_rsc_colocation_lh(resource_t * rsc_lh, resource_t * rsc_rh, rsc_colocation_t * constraint) { pe_err("Container %s cannot be colocated with anything", rsc_lh->id); } void container_rsc_colocation_rh(resource_t * rsc_lh, resource_t * rsc_rh, rsc_colocation_t * constraint) { pe_err("Container %s cannot be colocated with anything", rsc_rh->id); } enum pe_action_flags container_action_flags(action_t * action, node_t * node) { enum pe_action_flags flags = (pe_action_optional | pe_action_runnable | pe_action_pseudo); return flags; } enum pe_graph_flags container_update_actions(action_t * first, action_t * then, node_t * node, enum pe_action_flags flags, enum pe_action_flags filter, enum pe_ordering type) { enum pe_graph_flags changed = pe_graph_none; return changed; } void container_rsc_location(resource_t * rsc, rsc_to_node_t * constraint) { GListPtr gIter = rsc->children; pe_rsc_trace(rsc, "Processing location constraint %s for %s", constraint->id, rsc->id); native_rsc_location(rsc, constraint); for (; gIter != NULL; gIter = gIter->next) { resource_t *child_rsc = (resource_t *) gIter->data; child_rsc->cmds->rsc_location(child_rsc, constraint); } } void container_expand(resource_t * rsc, pe_working_set_t * data_set) { container_variant_data_t *container_data = NULL; CRM_CHECK(rsc != NULL, return); get_container_variant_data(container_data, rsc); for (GListPtr gIter = container_data->tuples; gIter != NULL; gIter = gIter->next) { container_grouping_t *tuple = (container_grouping_t *)gIter->data; CRM_ASSERT(tuple); if(tuple->ip) { tuple->ip->cmds->expand(tuple->ip, data_set); } if(tuple->child) { tuple->child->cmds->expand(tuple->child, data_set); } if(tuple->docker) { tuple->docker->cmds->expand(tuple->docker, data_set); } if(tuple->remote) { tuple->remote->cmds->expand(tuple->remote, data_set); } } } gboolean container_create_probe(resource_t * rsc, node_t * node, action_t * complete, gboolean force, pe_working_set_t * data_set) { bool any_created = FALSE; container_variant_data_t *container_data = NULL; CRM_CHECK(rsc != NULL, return FALSE); get_container_variant_data(container_data, rsc); for (GListPtr gIter = container_data->tuples; gIter != NULL; gIter = gIter->next) { container_grouping_t *tuple = (container_grouping_t *)gIter->data; CRM_ASSERT(tuple); if(tuple->ip) { any_created |= tuple->ip->cmds->create_probe(tuple->ip, node, complete, force, data_set); } - if(tuple->child) { + if(tuple->child && node->details == tuple->node->details) { any_created |= tuple->child->cmds->create_probe(tuple->child, node, complete, force, data_set); } if(tuple->docker) { any_created |= tuple->docker->cmds->create_probe(tuple->docker, node, complete, force, data_set); } if(FALSE && tuple->remote) { // TODO: Needed? any_created |= tuple->remote->cmds->create_probe(tuple->remote, node, complete, force, data_set); } } return any_created; } void container_append_meta(resource_t * rsc, xmlNode * xml) { } GHashTable * container_merge_weights(resource_t * rsc, const char *rhs, GHashTable * nodes, const char *attr, float factor, enum pe_weights flags) { return rsc_merge_weights(rsc, rhs, nodes, attr, factor, flags); } void container_LogActions( resource_t * rsc, pe_working_set_t * data_set, gboolean terminal) { container_variant_data_t *container_data = NULL; CRM_CHECK(rsc != NULL, return); get_container_variant_data(container_data, rsc); for (GListPtr gIter = container_data->tuples; gIter != NULL; gIter = gIter->next) { container_grouping_t *tuple = (container_grouping_t *)gIter->data; CRM_ASSERT(tuple); if(tuple->ip) { LogActions(tuple->ip, data_set, terminal); } if(tuple->docker) { LogActions(tuple->docker, data_set, terminal); } if(tuple->remote) { LogActions(tuple->remote, data_set, terminal); } if(tuple->child) { LogActions(tuple->child, data_set, terminal); } } }