Exemple #1
0
static action_t *
rsc_expand_action(action_t * action)
{
    action_t *result = action;

    if (action->rsc && action->rsc->variant >= pe_group) {
        /* Expand 'start' -> 'started' */
        char *uuid = NULL;
        gboolean notify = FALSE;

        if (action->rsc->parent == NULL) {
            /* Only outter-most resources have notification actions */
            notify = is_set(action->rsc->flags, pe_rsc_notify);
        }

        uuid = convert_non_atomic_uuid(action->uuid, action->rsc, notify, FALSE);
        if (uuid) {
            pe_rsc_trace(action->rsc, "Converting %s to %s %d", action->uuid, uuid,
                         is_set(action->rsc->flags, pe_rsc_notify));
            result = find_first_action(action->rsc->actions, uuid, NULL, NULL);
            if (result == NULL) {
                crm_err("Couldn't expand %s", action->uuid);
                result = action;
            }
            free(uuid);
        }
    }
    return result;
}
enum pe_graph_flags
group_update_actions(pe_action_t *first, pe_action_t *then, pe_node_t *node,
                     enum pe_action_flags flags, enum pe_action_flags filter,
                     enum pe_ordering type, pe_working_set_t *data_set)
{
    GListPtr gIter = then->rsc->children;
    enum pe_graph_flags changed = pe_graph_none;

    CRM_ASSERT(then->rsc != NULL);
    changed |= native_update_actions(first, then, node, flags, filter, type,
                                     data_set);

    for (; gIter != NULL; gIter = gIter->next) {
        resource_t *child = (resource_t *) gIter->data;
        action_t *child_action = find_first_action(child->actions, NULL, then->task, node);

        if (child_action) {
            changed |= child->cmds->update_actions(first, child_action, node,
                                                   flags, filter, type,
                                                   data_set);
        }
    }

    return changed;
}
/*
 * \internal
 * \brief Find any remote connection start relevant to an action
 *
 * \param[in] action  Action to chek
 *
 * \return If action is behind a remote connection, connection's start
 */
static pe_action_t *
find_remote_start(pe_action_t *action)
{
    if (action && action->node) {
        pe_resource_t *remote_rsc = action->node->details->remote_rsc;

        if (remote_rsc) {
            return find_first_action(remote_rsc->actions, NULL, RSC_START,
                                     NULL);
        }
    }
    return NULL;
}
Exemple #4
0
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;

    crm_trace("%s -> %s", first->uuid, then->uuid);

    if(can_interleave_actions(first, then)) {
        changed = container_update_interleave_actions(first, then, node, flags, filter, type);

    } else if(then->rsc) {
        GListPtr gIter = NULL;
        GListPtr children = NULL;

        // Handle the 'primitive' ordering case
        changed |= native_update_actions(first, then, node, flags, filter, type);

        // Now any children (or containers in the case of a bundle)
        children = get_containers_or_children(then->rsc);
        for (gIter = children; gIter != NULL; gIter = gIter->next) {
            resource_t *then_child = (resource_t *) gIter->data;
            enum pe_graph_flags then_child_changed = pe_graph_none;
            action_t *then_child_action = find_first_action(then_child->actions, NULL, then->task, node);

            if (then_child_action) {
                enum pe_action_flags then_child_flags = then_child->cmds->action_flags(then_child_action, node);

                if (is_set(then_child_flags, pe_action_runnable)) {
                    then_child_changed |=
                        then_child->cmds->update_actions(first, then_child_action, node, flags, filter, type);
                }
                changed |= then_child_changed;
                if (then_child_changed & pe_graph_updated_then) {
                    for (GListPtr lpc = then_child_action->actions_after; lpc != NULL; lpc = lpc->next) {
                        action_wrapper_t *next = (action_wrapper_t *) lpc->data;
                        update_action(next->action);
                    }
                }
            }
        }

        if(children != then->rsc->children) {
            g_list_free(children);
        }
    }
    return changed;
}
enum pe_action_flags
summary_action_flags(action_t * action, GListPtr children, node_t * node)
{
    GListPtr gIter = NULL;
    gboolean any_runnable = FALSE;
    gboolean check_runnable = TRUE;
    enum action_tasks task = clone_child_action(action);
    enum pe_action_flags flags = (pe_action_optional | pe_action_runnable | pe_action_pseudo);
    const char *task_s = task2text(task);

    for (gIter = children; gIter != NULL; gIter = gIter->next) {
        action_t *child_action = NULL;
        resource_t *child = (resource_t *) gIter->data;

        child_action = find_first_action(child->actions, NULL, task_s, child->children ? NULL : node);
        pe_rsc_trace(action->rsc, "Checking for %s in %s on %s (%s)", task_s, child->id,
                     node ? node->details->uname : "none", child_action?child_action->uuid:"NA");
        if (child_action) {
            enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);

            if (is_set(flags, pe_action_optional)
                && is_set(child_flags, pe_action_optional) == FALSE) {
                pe_rsc_trace(child, "%s is mandatory because of %s", action->uuid,
                             child_action->uuid);
                flags = crm_clear_bit(__FUNCTION__, __LINE__, action->rsc->id, flags, pe_action_optional);
                pe_clear_action_bit(action, pe_action_optional);
            }
            if (is_set(child_flags, pe_action_runnable)) {
                any_runnable = TRUE;
            }
        }
    }

    if (check_runnable && any_runnable == FALSE) {
        pe_rsc_trace(action->rsc, "%s is not runnable because no children are", action->uuid);
        flags = crm_clear_bit(__FUNCTION__, __LINE__, action->rsc->id, flags, pe_action_runnable);
        if (node == NULL) {
            pe_clear_action_bit(action, pe_action_runnable);
        }
    }

    return flags;
}
enum pe_action_flags
group_action_flags(action_t * action, node_t * node)
{
    GListPtr gIter = NULL;
    enum pe_action_flags flags = (pe_action_optional | pe_action_runnable | pe_action_pseudo);

    for (gIter = action->rsc->children; gIter != NULL; gIter = gIter->next) {
        resource_t *child = (resource_t *) gIter->data;
        enum action_tasks task = get_complex_task(child, action->task, TRUE);
        const char *task_s = task2text(task);
        action_t *child_action = find_first_action(child->actions, NULL, task_s, node);

        if (child_action) {
            enum pe_action_flags child_flags = child->cmds->action_flags(child_action, node);

            if (is_set(flags, pe_action_optional)
                && is_set(child_flags, pe_action_optional) == FALSE) {
                pe_rsc_trace(action->rsc, "%s is mandatory because of %s", action->uuid,
                             child_action->uuid);
                clear_bit(flags, pe_action_optional);
                pe_clear_action_bit(action, pe_action_optional);
            }
            if (safe_str_neq(task_s, action->task)
                && is_set(flags, pe_action_runnable)
                && is_set(child_flags, pe_action_runnable) == FALSE) {
                pe_rsc_trace(action->rsc, "%s is not runnable because of %s", action->uuid,
                             child_action->uuid);
                clear_bit(flags, pe_action_runnable);
                pe_clear_action_bit(action, pe_action_runnable);
            }

        } else if (task != stop_rsc && task != action_demote) {
            pe_rsc_trace(action->rsc, "%s is not runnable because of %s (not found in %s)",
                         action->uuid, task_s, child->id);
            clear_bit(flags, pe_action_runnable);
        }
    }

    return flags;
}
Exemple #7
0
void
create_notifications(resource_t * rsc, notify_data_t * n_data, pe_working_set_t * data_set)
{
    GListPtr gIter = NULL;
    action_t *stop = NULL;
    action_t *start = NULL;
    enum action_tasks task = text2task(n_data->action);

    if (rsc->children) {
        gIter = rsc->children;
        for (; gIter != NULL; gIter = gIter->next) {
            resource_t *child = (resource_t *) gIter->data;

            create_notifications(child, n_data, data_set);
        }
        return;
    }

    /* Copy notification details into standard ops */

    gIter = rsc->actions;
    for (; gIter != NULL; gIter = gIter->next) {
        action_t *op = (action_t *) gIter->data;

        if (is_set(op->flags, pe_action_optional) == FALSE && op->node != NULL) {
            enum action_tasks t = text2task(op->task);

            switch (t) {
                case start_rsc:
                case stop_rsc:
                case action_promote:
                case action_demote:
                    g_hash_table_foreach(n_data->keys, dup_attr, op->meta);
                    break;
                default:
                    break;
            }
        }
    }

    pe_rsc_trace(rsc, "Creating notifications for: %s.%s (%s->%s)",
                 n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));

    stop = find_first_action(rsc->actions, NULL, RSC_STOP, NULL);
    start = find_first_action(rsc->actions, NULL, RSC_START, NULL);

    /* stop / demote */
    if (rsc->role != RSC_ROLE_STOPPED) {
        if (task == stop_rsc || task == action_demote) {
            gIter = rsc->running_on;
            for (; gIter != NULL; gIter = gIter->next) {
                node_t *current_node = (node_t *) gIter->data;

                /* if this stop action is a pseudo action as a result of the current
                 * node being fenced, this stop action is implied by the fencing 
                 * action. There's no reason to send the fenced node a stop notification */ 
                if (stop &&
                    is_set(stop->flags, pe_action_pseudo) &&
                    current_node->details->unclean) {

                    continue;
                }

                pe_notify(rsc, current_node, n_data->pre, n_data->pre_done, n_data, data_set);
                if (task == action_demote || stop == NULL
                    || is_set(stop->flags, pe_action_optional)) {
                    pe_post_notify(rsc, current_node, n_data, data_set);
                }
            }
        }
    }

    /* start / promote */
    if (rsc->next_role != RSC_ROLE_STOPPED) {
        if (rsc->allocated_to == NULL) {
            pe_proc_err("Next role '%s' but %s is not allocated", role2text(rsc->next_role),
                        rsc->id);

        } else if (task == start_rsc || task == action_promote) {
            if (task != start_rsc || start == NULL || is_set(start->flags, pe_action_optional)) {
                pe_notify(rsc, rsc->allocated_to, n_data->pre, n_data->pre_done, n_data, data_set);
            }
            pe_post_notify(rsc, rsc->allocated_to, n_data, data_set);
        }
    }
}
void
create_notifications(resource_t * rsc, notify_data_t * n_data, pe_working_set_t * data_set)
{
    GListPtr gIter = NULL;
    action_t *stop = NULL;
    action_t *start = NULL;
    enum action_tasks task = text2task(n_data->action);

    if (rsc->children) {
        gIter = rsc->children;
        for (; gIter != NULL; gIter = gIter->next) {
            resource_t *child = (resource_t *) gIter->data;

            create_notifications(child, n_data, data_set);
        }
        return;
    }

    /* Copy notification details into standard ops */

    for (gIter = rsc->actions; gIter != NULL; gIter = gIter->next) {
        action_t *op = (action_t *) gIter->data;

        if (is_set(op->flags, pe_action_optional) == FALSE && op->node != NULL) {
            enum action_tasks t = text2task(op->task);

            switch (t) {
                case start_rsc:
                case stop_rsc:
                case action_promote:
                case action_demote:
                    add_notify_data_to_action_meta(n_data, op);
                    break;
                default:
                    break;
            }
        }
    }

    switch (task) {
        case start_rsc:
            if(g_list_length(n_data->start) == 0) {
                pe_rsc_trace(rsc, "Skipping empty notification for: %s.%s (%s->%s)",
                             n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
                return;
            }
            break;
        case action_promote:
            if(g_list_length(n_data->promote) == 0) {
                pe_rsc_trace(rsc, "Skipping empty notification for: %s.%s (%s->%s)",
                             n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
                return;
            }
            break;
        case action_demote:
            if(g_list_length(n_data->demote) == 0) {
                pe_rsc_trace(rsc, "Skipping empty notification for: %s.%s (%s->%s)",
                             n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));
                return;
            }
            break;
        default:
            /* We cannot do the same for stop_rsc/n_data->stop at it
             * might be implied by fencing
             */
            break;
    }

    pe_rsc_trace(rsc, "Creating notifications for: %s.%s (%s->%s)",
                 n_data->action, rsc->id, role2text(rsc->role), role2text(rsc->next_role));

    stop = find_first_action(rsc->actions, NULL, RSC_STOP, NULL);
    start = find_first_action(rsc->actions, NULL, RSC_START, NULL);

    /* stop / demote */
    if (rsc->role != RSC_ROLE_STOPPED) {
        if (task == stop_rsc || task == action_demote) {
            gIter = rsc->running_on;
            for (; gIter != NULL; gIter = gIter->next) {
                node_t *current_node = (node_t *) gIter->data;

                /* if this stop action is a pseudo action as a result of the current
                 * node being fenced, this stop action is implied by the fencing 
                 * action. There's no reason to send the fenced node a stop notification */ 
                if (stop &&
                    is_set(stop->flags, pe_action_pseudo) &&
                    (current_node->details->unclean || current_node->details->remote_requires_reset) ) {

                    continue;
                }

                pe_notify(rsc, current_node, n_data->pre, n_data->pre_done, n_data, data_set);
                if (task == action_demote || stop == NULL
                    || is_set(stop->flags, pe_action_optional)) {
                    pe_post_notify(rsc, current_node, n_data, data_set);
                }
            }
        }
    }

    /* start / promote */
    if (rsc->next_role != RSC_ROLE_STOPPED) {
        if (rsc->allocated_to == NULL) {
            pe_proc_err("Next role '%s' but %s is not allocated", role2text(rsc->next_role),
                        rsc->id);

        } else if (task == start_rsc || task == action_promote) {

            if (start) {
                pe_action_t *remote_start = find_remote_start(start);

                if (remote_start
                    && is_not_set(remote_start->flags, pe_action_runnable)) {
                    /* Start and promote actions for a clone instance behind
                     * a Pacemaker Remote connection happen after the
                     * connection starts. If the connection start is blocked, do
                     * not schedule notifications for these actions.
                     */
                    return;
                }
            }
            if (task != start_rsc || start == NULL || is_set(start->flags, pe_action_optional)) {
                pe_notify(rsc, rsc->allocated_to, n_data->pre, n_data->pre_done, n_data, data_set);
            }
            pe_post_notify(rsc, rsc->allocated_to, n_data, data_set);
        }
    }
}
Exemple #9
0
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 && node->details == tuple->node->details) {
            any_created |= tuple->child->cmds->create_probe(tuple->child, node, complete, force, data_set);
        }
        if(tuple->docker) {
            bool created = tuple->docker->cmds->create_probe(tuple->docker, node, complete, force, data_set);

            if(created) {
                any_created = TRUE;
                /* If we're limited to one replica per host (due to
                 * the lack of an IP range probably), then we don't
                 * want any of our peer containers starting until
                 * we've established that no other copies are already
                 * running.
                 *
                 * Partly this is to ensure that replicas_per_host is
                 * observed, but also to ensure that the containers
                 * don't fail to start because the necessary port
                 * mappings (which won't include an IP for uniqueness)
                 * are already taken
                 */

                for (GListPtr tIter = container_data->tuples; tIter != NULL && container_data->replicas_per_host == 1; tIter = tIter->next) {
                    container_grouping_t *other = (container_grouping_t *)tIter->data;

                    if ((other != tuple) && (other != NULL)
                        && (other->docker != NULL)) {

                        custom_action_order(tuple->docker, generate_op_key(tuple->docker->id, RSC_STATUS, 0), NULL,
                                            other->docker, generate_op_key(other->docker->id, RSC_START, 0), NULL,
                                            pe_order_optional|pe_order_same_node, data_set);
                    }
                }
            }
        }
        if (tuple->docker && tuple->remote
            && tuple->remote->cmds->create_probe(tuple->remote, node, complete,
                                                 force, data_set)) {

            /* Do not probe the remote resource until we know where docker is running
             * Required for REMOTE_CONTAINER_HACK to correctly probe remote resources
             */
            char *probe_uuid = generate_op_key(tuple->remote->id, RSC_STATUS, 0);
            action_t *probe = find_first_action(tuple->remote->actions, probe_uuid, NULL, node);

            free(probe_uuid);
            if (probe) {
                any_created = TRUE;
                crm_trace("Ordering %s probe on %s",
                          tuple->remote->id, node->details->uname);
                custom_action_order(tuple->docker,
                                    generate_op_key(tuple->docker->id, RSC_START, 0),
                                    NULL, tuple->remote, NULL, probe,
                                    pe_order_probe, data_set);
            }
        }
    }
    return any_created;
}
Exemple #10
0
static enum pe_graph_flags
container_update_interleave_actions(action_t * first, action_t * then, node_t * node, enum pe_action_flags flags,
                     enum pe_action_flags filter, enum pe_ordering type)
{
    GListPtr gIter = NULL;
    GListPtr children = NULL;
    gboolean current = FALSE;
    enum pe_graph_flags changed = pe_graph_none;

    /* Fix this - lazy */
    if (crm_ends_with(first->uuid, "_stopped_0")
        || crm_ends_with(first->uuid, "_demoted_0")) {
        current = TRUE;
    }

    children = get_containers_or_children(then->rsc);
    for (gIter = children; gIter != NULL; gIter = gIter->next) {
        resource_t *then_child = (resource_t *) gIter->data;
        resource_t *first_child = find_compatible_child(then_child, first->rsc, RSC_ROLE_UNKNOWN, current);
        if (first_child == NULL && current) {
            crm_trace("Ignore");

        } else if (first_child == NULL) {
            crm_debug("No match found for %s (%d / %s / %s)", then_child->id, current, first->uuid, then->uuid);

            /* Me no like this hack - but what else can we do?
             *
             * If there is no-one active or about to be active
             *   on the same node as then_child, then they must
             *   not be allowed to start
             */
            if (type & (pe_order_runnable_left | pe_order_implies_then) /* Mandatory */ ) {
                pe_rsc_info(then->rsc, "Inhibiting %s from being active", then_child->id);
                if(assign_node(then_child, NULL, TRUE)) {
                    changed |= pe_graph_updated_then;
                }
            }

        } else {
            pe_action_t *first_action = NULL;
            pe_action_t *then_action = NULL;

            enum action_tasks task = clone_child_action(first);
            const char *first_task = task2text(task);

            container_grouping_t *first_tuple = tuple_for_docker(first->rsc, first_child, node);
            container_grouping_t *then_tuple = tuple_for_docker(then->rsc, then_child, node);

            if(strstr(first->task, "stop") && first_tuple && first_tuple->child) {
                /* Except for 'stopped' we should be looking at the
                 * in-container resource, actions for the child will
                 * happen later and are therefor more likely to align
                 * with the user's intent.
                 */
                first_action = find_first_action(first_tuple->child->actions, NULL, task2text(task), node);
            } else {
                first_action = find_first_action(first_child->actions, NULL, task2text(task), node);
            }

            if(strstr(then->task, "mote") && then_tuple && then_tuple->child) {
                /* Promote/demote actions will never be found for the
                 * docker resource, look in the child instead
                 *
                 * Alternatively treat:
                 *  'XXXX then promote YYYY' as 'XXXX then start container for YYYY', and
                 *  'demote XXXX then stop YYYY' as 'stop container for XXXX then stop YYYY'
                 */
                then_action = find_first_action(then_tuple->child->actions, NULL, then->task, node);
            } else {
                then_action = find_first_action(then_child->actions, NULL, then->task, node);
            }

            if (first_action == NULL) {
                if (is_not_set(first_child->flags, pe_rsc_orphan)
                    && crm_str_eq(first_task, RSC_STOP, TRUE) == FALSE
                    && crm_str_eq(first_task, RSC_DEMOTE, TRUE) == FALSE) {
                    crm_err("Internal error: No action found for %s in %s (first)",
                            first_task, first_child->id);

                } else {
                    crm_trace("No action found for %s in %s%s (first)",
                              first_task, first_child->id,
                              is_set(first_child->flags, pe_rsc_orphan) ? " (ORPHAN)" : "");
                }
                continue;
            }

            /* We're only interested if 'then' is neither stopping nor being demoted */ 
            if (then_action == NULL) {
                if (is_not_set(then_child->flags, pe_rsc_orphan)
                    && crm_str_eq(then->task, RSC_STOP, TRUE) == FALSE
                    && crm_str_eq(then->task, RSC_DEMOTE, TRUE) == FALSE) {
                    crm_err("Internal error: No action found for %s in %s (then)",
                            then->task, then_child->id);

                } else {
                    crm_trace("No action found for %s in %s%s (then)",
                              then->task, then_child->id,
                              is_set(then_child->flags, pe_rsc_orphan) ? " (ORPHAN)" : "");
                }
                continue;
            }

            if (order_actions(first_action, then_action, type)) {
                crm_debug("Created constraint for %s (%d) -> %s (%d) %.6x",
                          first_action->uuid, is_set(first_action->flags, pe_action_optional),
                          then_action->uuid, is_set(then_action->flags, pe_action_optional), type);
                changed |= (pe_graph_updated_first | pe_graph_updated_then);
            }
            if(first_action && then_action) {
                changed |= then_child->cmds->update_actions(first_action, then_action, node,
                                                            first_child->cmds->action_flags(first_action, node),
                                                            filter, type);
            } else {
                crm_err("Nothing found either for %s (%p) or %s (%p) %s",
                        first_child->id, first_action,
                        then_child->id, then_action, task2text(task));
            }
        }
    }

    if(children != then->rsc->children) {
        g_list_free(children);
    }
    return changed;
}
Exemple #11
0
/*
 * ASSUMES: rootObj is not NULL
 *		- done is FALSE
 */
static int
travP_find_first(ABTraversal trav)
{
#define rootObj (trav->rootObj)
#define curObj (trav->curObj)
    curObj = NULL;

    switch (travP_get_qualifier(trav))
    {
    case AB_TRAV_ACTIONS_FOR_OBJ:
        curObj= find_first_action(rootObj, trav);
        break;

    case AB_TRAV_CHILDREN:
    case AB_TRAV_SALIENT_CHILDREN:
    case AB_TRAV_SALIENT_UI_CHILDREN:
        curObj= travP_obj_first_child(rootObj, trav);
        break;

    case AB_TRAV_COMP_SUBOBJS:
        if (obj_is_root(rootObj))
        {
            curObj = rootObj;
        }
        break;

    case AB_TRAV_ITEMS_FOR_OBJ:
        curObj= find_first_item(rootObj);
        break;

    case AB_TRAV_MODULES:
        curObj= obj_is_module(rootObj)?
                rootObj
                :
                find_first_child_of_type(rootObj, trav, AB_TYPE_MODULE);
        break;

    case AB_TRAV_PARENTS:
        travP_find_first_for_parents(trav);
        break;

    case AB_TRAV_SIBLINGS:
    {
        ABObj	prevSibling= NULL;
        curObj= rootObj;
        while ((prevSibling= travP_obj_prev_sibling(curObj, trav)) != NULL)
        {
            curObj= prevSibling;
        }
    }
    break;

    default:
        curObj= rootObj;
        break;
    }

    return 0;
#undef rootObj
#undef curObj
}