org.apache.ambari.server.controller.internal.UpgradeResourceProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.ambari.server.controller.internal.UpgradeResourceProvider.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.ambari.server.controller.internal;

import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOOKS_FOLDER;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_LOCATION;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_PACKAGE_FOLDER;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.VERSION;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.Role;
import org.apache.ambari.server.RoleCommand;
import org.apache.ambari.server.StaticallyInject;
import org.apache.ambari.server.actionmanager.ActionManager;
import org.apache.ambari.server.actionmanager.HostRoleCommand;
import org.apache.ambari.server.actionmanager.HostRoleStatus;
import org.apache.ambari.server.actionmanager.RequestFactory;
import org.apache.ambari.server.actionmanager.Stage;
import org.apache.ambari.server.actionmanager.StageFactory;
import org.apache.ambari.server.api.resources.UpgradeResourceDefinition;
import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.controller.ActionExecutionContext;
import org.apache.ambari.server.controller.AmbariActionExecutionHelper;
import org.apache.ambari.server.controller.AmbariCustomCommandExecutionHelper;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.ExecuteCommandJson;
import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
import org.apache.ambari.server.controller.spi.NoSuchResourceException;
import org.apache.ambari.server.controller.spi.Predicate;
import org.apache.ambari.server.controller.spi.Request;
import org.apache.ambari.server.controller.spi.RequestStatus;
import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
import org.apache.ambari.server.controller.spi.SystemException;
import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
import org.apache.ambari.server.orm.dao.HostRoleCommandStatusSummaryDTO;
import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
import org.apache.ambari.server.orm.dao.RequestDAO;
import org.apache.ambari.server.orm.dao.UpgradeDAO;
import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
import org.apache.ambari.server.orm.entities.RequestEntity;
import org.apache.ambari.server.orm.entities.UpgradeEntity;
import org.apache.ambari.server.orm.entities.UpgradeGroupEntity;
import org.apache.ambari.server.orm.entities.UpgradeItemEntity;
import org.apache.ambari.server.stack.MasterHostResolver;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.ConfigHelper;
import org.apache.ambari.server.state.ServiceInfo;
import org.apache.ambari.server.state.StackId;
import org.apache.ambari.server.state.StackInfo;
import org.apache.ambari.server.state.UpgradeContext;
import org.apache.ambari.server.state.UpgradeHelper;
import org.apache.ambari.server.state.UpgradeHelper.UpgradeGroupHolder;
import org.apache.ambari.server.state.stack.UpgradePack;
import org.apache.ambari.server.state.stack.upgrade.ConfigureTask;
import org.apache.ambari.server.state.stack.upgrade.Direction;
import org.apache.ambari.server.state.stack.upgrade.ManualTask;
import org.apache.ambari.server.state.stack.upgrade.ServerSideActionTask;
import org.apache.ambari.server.state.stack.upgrade.StageWrapper;
import org.apache.ambari.server.state.stack.upgrade.Task;
import org.apache.ambari.server.state.stack.upgrade.TaskWrapper;
import org.apache.ambari.server.state.svccomphost.ServiceComponentHostServerActionEvent;
import org.apache.ambari.server.utils.StageUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Inject;
import com.google.inject.Provider;

/**
 * Manages the ability to start and get status of upgrades.
 */
@StaticallyInject
public class UpgradeResourceProvider extends AbstractControllerResourceProvider {

    protected static final String UPGRADE_CLUSTER_NAME = "Upgrade/cluster_name";
    protected static final String UPGRADE_VERSION = "Upgrade/repository_version";
    protected static final String UPGRADE_REQUEST_ID = "Upgrade/request_id";
    // TODO : Get rid of the UPGRADE_FORCE_DOWNGRADE property... should use downgrade create directive
    protected static final String UPGRADE_FORCE_DOWNGRADE = "Upgrade/force_downgrade";
    protected static final String UPGRADE_FROM_VERSION = "Upgrade/from_version";
    protected static final String UPGRADE_TO_VERSION = "Upgrade/to_version";
    protected static final String UPGRADE_DIRECTION = "Upgrade/direction";
    protected static final String UPGRADE_REQUEST_STATUS = "Upgrade/request_status";
    protected static final String UPGRADE_ABORT_REASON = "Upgrade/abort_reason";

    /*
     * Lifted from RequestResourceProvider
     */
    private static final String REQUEST_CONTEXT_ID = "Upgrade/request_context";
    private static final String REQUEST_TYPE_ID = "Upgrade/type";
    private static final String REQUEST_CREATE_TIME_ID = "Upgrade/create_time";
    private static final String REQUEST_START_TIME_ID = "Upgrade/start_time";
    private static final String REQUEST_END_TIME_ID = "Upgrade/end_time";
    private static final String REQUEST_EXCLUSIVE_ID = "Upgrade/exclusive";

    private static final String REQUEST_PROGRESS_PERCENT_ID = "Upgrade/progress_percent";
    private static final String REQUEST_STATUS_PROPERTY_ID = "Upgrade/request_status";

    private static final Set<String> PK_PROPERTY_IDS = new HashSet<String>(
            Arrays.asList(UPGRADE_REQUEST_ID, UPGRADE_CLUSTER_NAME));
    private static final Set<String> PROPERTY_IDS = new HashSet<String>();

    private static final String COMMAND_PARAM_VERSION = VERSION;
    private static final String COMMAND_PARAM_CLUSTER_NAME = "clusterName";
    private static final String COMMAND_PARAM_DIRECTION = "upgrade_direction";
    private static final String COMMAND_PARAM_RESTART_TYPE = "restart_type";
    private static final String COMMAND_PARAM_TASKS = "tasks";
    private static final String COMMAND_PARAM_STRUCT_OUT = "structured_out";

    private static final String DEFAULT_REASON_TEMPLATE = "Aborting upgrade %s";

    private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = new HashMap<Resource.Type, String>();

    @Inject
    private static UpgradeDAO s_upgradeDAO = null;

    @Inject
    private static Provider<AmbariMetaInfo> s_metaProvider = null;

    @Inject
    private static RepositoryVersionDAO s_repoVersionDAO = null;

    @Inject
    private static Provider<RequestFactory> s_requestFactory;

    @Inject
    private static Provider<StageFactory> s_stageFactory;

    @Inject
    private static Provider<AmbariActionExecutionHelper> s_actionExecutionHelper;

    @Inject
    private static Provider<AmbariCustomCommandExecutionHelper> s_commandExecutionHelper;

    @Inject
    private static RequestDAO s_requestDAO = null;

    @Inject
    private static HostRoleCommandDAO s_hostRoleCommandDAO = null;

    /**
     * Used to generated the correct tasks and stages during an upgrade.
     */
    @Inject
    private static UpgradeHelper s_upgradeHelper;

    @Inject
    private static Configuration s_configuration;

    static {
        // properties
        PROPERTY_IDS.add(UPGRADE_CLUSTER_NAME);
        PROPERTY_IDS.add(UPGRADE_VERSION);
        PROPERTY_IDS.add(UPGRADE_REQUEST_ID);
        PROPERTY_IDS.add(UPGRADE_FORCE_DOWNGRADE);
        PROPERTY_IDS.add(UPGRADE_FROM_VERSION);
        PROPERTY_IDS.add(UPGRADE_TO_VERSION);
        PROPERTY_IDS.add(UPGRADE_DIRECTION);

        PROPERTY_IDS.add(REQUEST_CONTEXT_ID);
        PROPERTY_IDS.add(REQUEST_CREATE_TIME_ID);
        PROPERTY_IDS.add(REQUEST_END_TIME_ID);
        PROPERTY_IDS.add(REQUEST_EXCLUSIVE_ID);
        PROPERTY_IDS.add(REQUEST_PROGRESS_PERCENT_ID);
        PROPERTY_IDS.add(REQUEST_START_TIME_ID);
        PROPERTY_IDS.add(REQUEST_STATUS_PROPERTY_ID);
        PROPERTY_IDS.add(REQUEST_TYPE_ID);

        // keys
        KEY_PROPERTY_IDS.put(Resource.Type.Upgrade, UPGRADE_REQUEST_ID);
        KEY_PROPERTY_IDS.put(Resource.Type.Cluster, UPGRADE_CLUSTER_NAME);
    }

    private static final Logger LOG = LoggerFactory.getLogger(UpgradeResourceProvider.class);

    /**
     * Constructor.
     *
     * @param controller  the controller
     */
    UpgradeResourceProvider(AmbariManagementController controller) {
        super(PROPERTY_IDS, KEY_PROPERTY_IDS, controller);
    }

    @Override
    public RequestStatus createResources(final Request request) throws SystemException,
            UnsupportedPropertyException, ResourceAlreadyExistsException, NoSuchParentResourceException {

        Set<Map<String, Object>> requestMaps = request.getProperties();

        if (requestMaps.size() > 1) {
            throw new SystemException("Can only initiate one upgrade per request.");
        }

        // !!! above check ensures only one
        final Map<String, Object> requestMap = requestMaps.iterator().next();
        final Map<String, String> requestInfoProps = request.getRequestInfoProperties();

        UpgradeEntity entity = createResources(new Command<UpgradeEntity>() {
            @Override
            public UpgradeEntity invoke() throws AmbariException {
                String forceDowngrade = requestInfoProps.get(UpgradeResourceDefinition.DOWNGRADE_DIRECTIVE);

                // check the property if the directive is not specified...
                if (forceDowngrade == null) {
                    forceDowngrade = (String) requestMap.get(UPGRADE_FORCE_DOWNGRADE);
                }

                Direction direction = Boolean.parseBoolean(forceDowngrade) ? Direction.DOWNGRADE
                        : Direction.UPGRADE;

                UpgradePack up = validateRequest(direction, requestMap);

                return createUpgrade(direction, up, requestMap);
            }
        });

        if (null == entity) {
            throw new SystemException("Could not load upgrade");
        }

        notifyCreate(Resource.Type.Upgrade, request);

        Resource res = new ResourceImpl(Resource.Type.Upgrade);
        res.setProperty(UPGRADE_REQUEST_ID, entity.getRequestId());
        return new RequestStatusImpl(null, Collections.singleton(res));
    }

    @Override
    public Set<Resource> getResources(Request request, Predicate predicate) throws SystemException,
            UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {

        Set<Resource> results = new HashSet<Resource>();
        Set<String> requestPropertyIds = getRequestPropertyIds(request, predicate);

        for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
            String clusterName = (String) propertyMap.get(UPGRADE_CLUSTER_NAME);

            if (null == clusterName || clusterName.isEmpty()) {
                throw new IllegalArgumentException("The cluster name is required when querying for upgrades");
            }

            Cluster cluster;
            try {
                cluster = getManagementController().getClusters().getCluster(clusterName);
            } catch (AmbariException e) {
                throw new NoSuchResourceException(String.format("Cluster %s could not be loaded", clusterName));
            }

            List<UpgradeEntity> upgrades = new ArrayList<UpgradeEntity>();

            String upgradeIdStr = (String) propertyMap.get(UPGRADE_REQUEST_ID);
            if (null != upgradeIdStr) {
                UpgradeEntity upgrade = s_upgradeDAO.findUpgradeByRequestId(Long.valueOf(upgradeIdStr));

                if (null != upgrade) {
                    upgrades.add(upgrade);
                }
            } else {
                upgrades = s_upgradeDAO.findUpgrades(cluster.getClusterId());
            }

            for (UpgradeEntity entity : upgrades) {
                Resource r = toResource(entity, clusterName, requestPropertyIds);
                results.add(r);

                RequestEntity rentity = s_requestDAO.findByPK(entity.getRequestId());

                setResourceProperty(r, REQUEST_CONTEXT_ID, rentity.getRequestContext(), requestPropertyIds);
                setResourceProperty(r, REQUEST_TYPE_ID, rentity.getRequestType(), requestPropertyIds);
                setResourceProperty(r, REQUEST_CREATE_TIME_ID, rentity.getCreateTime(), requestPropertyIds);
                setResourceProperty(r, REQUEST_START_TIME_ID, rentity.getStartTime(), requestPropertyIds);
                setResourceProperty(r, REQUEST_END_TIME_ID, rentity.getEndTime(), requestPropertyIds);
                setResourceProperty(r, REQUEST_EXCLUSIVE_ID, rentity.isExclusive(), requestPropertyIds);

                Map<Long, HostRoleCommandStatusSummaryDTO> summary = s_hostRoleCommandDAO
                        .findAggregateCounts(entity.getRequestId());

                CalculatedStatus calc = CalculatedStatus.statusFromStageSummary(summary, summary.keySet());

                setResourceProperty(r, REQUEST_STATUS_PROPERTY_ID, calc.getStatus(), requestPropertyIds);
                setResourceProperty(r, REQUEST_PROGRESS_PERCENT_ID, calc.getPercent(), requestPropertyIds);
            }
        }

        return results;
    }

    @Override
    public RequestStatus updateResources(final Request request, Predicate predicate) throws SystemException,
            UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {

        Set<Map<String, Object>> requestMaps = request.getProperties();

        if (requestMaps.size() > 1) {
            throw new SystemException("Can only update one upgrade per request.");
        }

        // !!! above check ensures only one
        final Map<String, Object> propertyMap = requestMaps.iterator().next();

        String requestId = (String) propertyMap.get(UPGRADE_REQUEST_ID);
        if (null == requestId) {
            throw new IllegalArgumentException(String.format("%s is required", UPGRADE_REQUEST_ID));
        }

        String requestStatus = (String) propertyMap.get(UPGRADE_REQUEST_STATUS);
        if (null == requestStatus) {
            throw new IllegalArgumentException(String.format("%s is required", UPGRADE_REQUEST_STATUS));
        }

        HostRoleStatus status = HostRoleStatus.valueOf(requestStatus);
        if (status != HostRoleStatus.ABORTED) {
            throw new IllegalArgumentException(
                    String.format("Cannot set status %s, only %s is allowed", status, HostRoleStatus.ABORTED));
        }

        String reason = (String) propertyMap.get(UPGRADE_ABORT_REASON);
        if (null == reason) {
            reason = String.format(DEFAULT_REASON_TEMPLATE, requestId);
        }

        ActionManager actionManager = getManagementController().getActionManager();
        List<org.apache.ambari.server.actionmanager.Request> requests = actionManager
                .getRequests(Collections.singletonList(Long.valueOf(requestId)));

        org.apache.ambari.server.actionmanager.Request internalRequest = requests.get(0);

        HostRoleStatus internalStatus = CalculatedStatus.statusFromStages(internalRequest.getStages()).getStatus();

        if (!internalStatus.isCompletedState()) {
            actionManager.cancelRequest(internalRequest.getRequestId(), reason);
        }

        return getRequestStatus(null);
    }

    @Override
    public RequestStatus deleteResources(Predicate predicate) throws SystemException, UnsupportedPropertyException,
            NoSuchResourceException, NoSuchParentResourceException {
        throw new SystemException("Cannot delete Upgrades");
    }

    @Override
    protected Set<String> getPKPropertyIds() {
        return PK_PROPERTY_IDS;
    }

    private Resource toResource(UpgradeEntity entity, String clusterName, Set<String> requestedIds) {
        ResourceImpl resource = new ResourceImpl(Resource.Type.Upgrade);

        setResourceProperty(resource, UPGRADE_CLUSTER_NAME, clusterName, requestedIds);
        setResourceProperty(resource, UPGRADE_REQUEST_ID, entity.getRequestId(), requestedIds);
        setResourceProperty(resource, UPGRADE_FROM_VERSION, entity.getFromVersion(), requestedIds);
        setResourceProperty(resource, UPGRADE_TO_VERSION, entity.getToVersion(), requestedIds);
        setResourceProperty(resource, UPGRADE_DIRECTION, entity.getDirection(), requestedIds);

        return resource;
    }

    /**
     * Validates a singular API request.
     *
     * @param requestMap the map of properties
     * @return the validated upgrade pack
     * @throws AmbariException
     */
    private UpgradePack validateRequest(Direction direction, Map<String, Object> requestMap)
            throws AmbariException {
        String clusterName = (String) requestMap.get(UPGRADE_CLUSTER_NAME);
        String version = (String) requestMap.get(UPGRADE_VERSION);
        String versionForUpgradePack = (String) requestMap.get(UPGRADE_FROM_VERSION);

        if (null == clusterName) {
            throw new AmbariException(String.format("%s is required", UPGRADE_CLUSTER_NAME));
        }

        if (null == version) {
            throw new AmbariException(String.format("%s is required", UPGRADE_VERSION));
        }

        Cluster cluster = getManagementController().getClusters().getCluster(clusterName);
        StackId stack = cluster.getDesiredStackVersion();

        String repoVersion = version;

        if (direction.isDowngrade() && null != versionForUpgradePack) {
            repoVersion = versionForUpgradePack;
        }

        RepositoryVersionEntity versionEntity = s_repoVersionDAO.findByStackAndVersion(stack.getStackId(),
                repoVersion);

        if (null == versionEntity) {
            throw new AmbariException(
                    String.format("Version %s for stack %s was not found", repoVersion, stack.getStackVersion()));
        }

        Map<String, UpgradePack> packs = s_metaProvider.get().getUpgradePacks(stack.getStackName(),
                stack.getStackVersion());

        UpgradePack up = packs.get(versionEntity.getUpgradePackage());

        if (null == up) {
            throw new AmbariException(
                    String.format("Unable to perform %s.  Could not locate upgrade pack %s for version %s",
                            direction.getText(false), versionEntity.getUpgradePackage(), repoVersion));
        }

        // !!! validate all hosts have the version installed

        return up;
    }

    /**
     * Inject variables into the {@link org.apache.ambari.server.orm.entities.UpgradeItemEntity}, whose
     * tasks may use strings like {{configType/propertyName}} that need to be retrieved from the properties.
     * @param configHelper Configuration Helper
     * @param cluster Cluster
     * @param upgradeItem the item whose tasks will be injected.
     */
    private void injectVariables(ConfigHelper configHelper, Cluster cluster, UpgradeItemEntity upgradeItem) {
        final String regexp = "(\\{\\{.*?\\}\\})";

        String task = upgradeItem.getTasks();
        if (task != null && !task.isEmpty()) {
            Matcher m = Pattern.compile(regexp).matcher(task);
            while (m.find()) {
                String origVar = m.group(1);
                String configValue = configHelper.getPlaceholderValueFromDesiredConfigurations(cluster, origVar);

                if (null != configValue) {
                    task = task.replace(origVar, configValue);
                } else {
                    LOG.error("Unable to retrieve value for {}", origVar);
                }

            }
            upgradeItem.setTasks(task);
        }
    }

    private UpgradeEntity createUpgrade(Direction direction, UpgradePack pack, Map<String, Object> requestMap)
            throws AmbariException {

        String clusterName = (String) requestMap.get(UPGRADE_CLUSTER_NAME);

        if (null == clusterName) {
            throw new AmbariException(String.format("%s is required", UPGRADE_CLUSTER_NAME));
        }

        Cluster cluster = getManagementController().getClusters().getCluster(clusterName);
        ConfigHelper configHelper = getManagementController().getConfigHelper();

        // the version being upgraded or downgraded to (ie hdp-2.2.1.0-1234)
        final String version = (String) requestMap.get(UPGRADE_VERSION);

        MasterHostResolver resolver = direction.isUpgrade() ? new MasterHostResolver(configHelper, cluster)
                : new MasterHostResolver(configHelper, cluster, version);

        UpgradeContext ctx = new UpgradeContext(resolver, version, direction);

        List<UpgradeGroupHolder> groups = s_upgradeHelper.createSequence(pack, ctx);

        if (groups.isEmpty()) {
            throw new AmbariException("There are no groupings available");
        }

        List<UpgradeGroupEntity> groupEntities = new ArrayList<UpgradeGroupEntity>();
        RequestStageContainer req = createRequest(direction, version);

        for (UpgradeGroupHolder group : groups) {
            UpgradeGroupEntity groupEntity = new UpgradeGroupEntity();
            groupEntity.setName(group.name);
            groupEntity.setTitle(group.title);
            boolean skippable = group.skippable;
            boolean allowRetry = group.allowRetry;

            List<UpgradeItemEntity> itemEntities = new ArrayList<UpgradeItemEntity>();

            for (StageWrapper wrapper : group.items) {
                if (wrapper.getType() == StageWrapper.Type.SERVER_SIDE_ACTION) {
                    // !!! each stage is guaranteed to be of one type.  but because there
                    // is a bug that prevents one stage with multiple tasks assigned for the same host,
                    // break them out into individual stages.

                    for (TaskWrapper taskWrapper : wrapper.getTasks()) {
                        for (Task task : taskWrapper.getTasks()) {
                            UpgradeItemEntity itemEntity = new UpgradeItemEntity();
                            itemEntity.setText(wrapper.getText());
                            itemEntity.setTasks(wrapper.getTasksJson());
                            itemEntity.setHosts(wrapper.getHostsJson());
                            itemEntities.add(itemEntity);

                            injectVariables(configHelper, cluster, itemEntity);

                            makeServerSideStage(ctx, req, itemEntity, (ServerSideActionTask) task, skippable,
                                    allowRetry);
                        }
                    }
                } else {
                    UpgradeItemEntity itemEntity = new UpgradeItemEntity();
                    itemEntity.setText(wrapper.getText());
                    itemEntity.setTasks(wrapper.getTasksJson());
                    itemEntity.setHosts(wrapper.getHostsJson());
                    itemEntities.add(itemEntity);

                    injectVariables(configHelper, cluster, itemEntity);

                    // upgrade items match a stage
                    createStage(ctx, req, itemEntity, wrapper, skippable, allowRetry);
                }
            }

            groupEntity.setItems(itemEntities);

            groupEntities.add(groupEntity);

        }

        UpgradeEntity entity = new UpgradeEntity();
        entity.setFromVersion(cluster.getCurrentClusterVersion().getRepositoryVersion().getVersion());
        entity.setToVersion(version);
        entity.setUpgradeGroups(groupEntities);
        entity.setClusterId(Long.valueOf(cluster.getClusterId()));
        entity.setDirection(direction);

        req.getRequestStatusResponse();

        entity.setRequestId(req.getId());

        req.persist();

        s_upgradeDAO.create(entity);

        return entity;
    }

    private RequestStageContainer createRequest(Direction direction, String version) {
        ActionManager actionManager = getManagementController().getActionManager();

        RequestStageContainer requestStages = new RequestStageContainer(actionManager.getNextRequestId(), null,
                s_requestFactory.get(), actionManager);
        requestStages.setRequestContext(String.format("%s to %s", direction.getVerb(true), version));

        return requestStages;
    }

    private void createStage(UpgradeContext context, RequestStageContainer request, UpgradeItemEntity entity,
            StageWrapper wrapper, boolean skippable, boolean allowRetry) throws AmbariException {

        switch (wrapper.getType()) {
        case RESTART:
            makeRestartStage(context, request, entity, wrapper, skippable, allowRetry);
            break;
        case RU_TASKS:
            makeActionStage(context, request, entity, wrapper, skippable, allowRetry);
            break;
        case SERVICE_CHECK:
            makeServiceCheckStage(context, request, entity, wrapper, skippable, allowRetry);
            break;
        default:
            break;
        }
    }

    private void makeActionStage(UpgradeContext context, RequestStageContainer request, UpgradeItemEntity entity,
            StageWrapper wrapper, boolean skippable, boolean allowRetry) throws AmbariException {

        if (0 == wrapper.getHosts().size()) {
            throw new AmbariException(
                    String.format("Cannot create action for '%s' with no hosts", wrapper.getText()));
        }

        Cluster cluster = context.getCluster();

        // add each host to this stage
        RequestResourceFilter filter = new RequestResourceFilter("", "", new ArrayList<String>(wrapper.getHosts()));

        Map<String, String> params = new HashMap<String, String>();
        params.put(COMMAND_PARAM_TASKS, entity.getTasks());
        params.put(COMMAND_PARAM_VERSION, context.getVersion());
        params.put(COMMAND_PARAM_DIRECTION, context.getDirection().name().toLowerCase());

        // Because custom task may end up calling a script/function inside a service, it is necessary to set the
        // service_package_folder and hooks_folder params.
        AmbariMetaInfo ambariMetaInfo = s_metaProvider.get();
        StackId stackId = cluster.getDesiredStackVersion();
        StackInfo stackInfo = ambariMetaInfo.getStack(stackId.getStackName(), stackId.getStackVersion());
        if (wrapper.getTasks() != null && wrapper.getTasks().size() > 0) {
            String serviceName = wrapper.getTasks().get(0).getService();
            ServiceInfo serviceInfo = ambariMetaInfo.getService(stackId.getStackName(), stackId.getStackVersion(),
                    serviceName);
            params.put(SERVICE_PACKAGE_FOLDER, serviceInfo.getServicePackageFolder());
            params.put(HOOKS_FOLDER, stackInfo.getStackHooksFolder());
        }

        ActionExecutionContext actionContext = new ActionExecutionContext(cluster.getClusterName(),
                "ru_execute_tasks", Collections.singletonList(filter), params);
        actionContext.setIgnoreMaintenance(true);
        actionContext.setTimeout(Short.valueOf(s_configuration.getDefaultAgentTaskTimeout(false)));

        Map<String, String> hostLevelParams = new HashMap<String, String>();
        hostLevelParams.put(JDK_LOCATION, getManagementController().getJdkResourceUrl());

        ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext, cluster);

        Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari",
                cluster.getClusterName(), cluster.getClusterId(), entity.getText(), jsons.getClusterHostInfo(),
                jsons.getCommandParamsForStage(), jsons.getHostParamsForStage());

        stage.setSkippable(skippable);

        long stageId = request.getLastStageId() + 1;
        if (0L == stageId) {
            stageId = 1L;
        }
        stage.setStageId(stageId);
        entity.setStageId(Long.valueOf(stageId));

        s_actionExecutionHelper.get().addExecutionCommandsToStage(actionContext, stage, allowRetry);

        // need to set meaningful text on the command
        for (Map<String, HostRoleCommand> map : stage.getHostRoleCommands().values()) {
            for (HostRoleCommand hrc : map.values()) {
                hrc.setCommandDetail(entity.getText());
            }
        }

        request.addStages(Collections.singletonList(stage));
    }

    private void makeRestartStage(UpgradeContext context, RequestStageContainer request, UpgradeItemEntity entity,
            StageWrapper wrapper, boolean skippable, boolean allowRetry) throws AmbariException {

        Cluster cluster = context.getCluster();

        List<RequestResourceFilter> filters = new ArrayList<RequestResourceFilter>();

        for (TaskWrapper tw : wrapper.getTasks()) {
            // add each host to this stage
            filters.add(new RequestResourceFilter(tw.getService(), tw.getComponent(),
                    new ArrayList<String>(tw.getHosts())));
        }

        Map<String, String> restartCommandParams = new HashMap<String, String>();
        restartCommandParams.put(COMMAND_PARAM_RESTART_TYPE, "rolling_upgrade");
        restartCommandParams.put(COMMAND_PARAM_VERSION, context.getVersion());
        restartCommandParams.put(COMMAND_PARAM_DIRECTION, context.getDirection().name().toLowerCase());

        ActionExecutionContext actionContext = new ActionExecutionContext(cluster.getClusterName(), "RESTART",
                filters, restartCommandParams);
        actionContext.setTimeout(Short.valueOf(s_configuration.getDefaultAgentTaskTimeout(false)));
        actionContext.setIgnoreMaintenance(true);

        ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext, cluster);

        Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari",
                cluster.getClusterName(), cluster.getClusterId(), entity.getText(), jsons.getClusterHostInfo(),
                jsons.getCommandParamsForStage(), jsons.getHostParamsForStage());

        stage.setSkippable(skippable);

        long stageId = request.getLastStageId() + 1;
        if (0L == stageId) {
            stageId = 1L;
        }
        stage.setStageId(stageId);
        entity.setStageId(Long.valueOf(stageId));

        Map<String, String> requestParams = new HashMap<String, String>();
        requestParams.put("command", "RESTART");

        s_commandExecutionHelper.get().addExecutionCommandsToStage(actionContext, stage, requestParams, allowRetry);

        request.addStages(Collections.singletonList(stage));
    }

    private void makeServiceCheckStage(UpgradeContext context, RequestStageContainer request,
            UpgradeItemEntity entity, StageWrapper wrapper, boolean skippable, boolean allowRetry)
            throws AmbariException {

        List<RequestResourceFilter> filters = new ArrayList<RequestResourceFilter>();

        for (TaskWrapper tw : wrapper.getTasks()) {
            filters.add(new RequestResourceFilter(tw.getService(), "", Collections.<String>emptyList()));
        }

        Cluster cluster = context.getCluster();

        Map<String, String> commandParams = new HashMap<String, String>();
        commandParams.put(COMMAND_PARAM_VERSION, context.getVersion());
        commandParams.put(COMMAND_PARAM_DIRECTION, context.getDirection().name().toLowerCase());

        ActionExecutionContext actionContext = new ActionExecutionContext(cluster.getClusterName(), "SERVICE_CHECK",
                filters, commandParams);
        actionContext.setTimeout(Short.valueOf(s_configuration.getDefaultAgentTaskTimeout(false)));
        actionContext.setIgnoreMaintenance(true);

        ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext, cluster);

        Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari",
                cluster.getClusterName(), cluster.getClusterId(), entity.getText(), jsons.getClusterHostInfo(),
                jsons.getCommandParamsForStage(), jsons.getHostParamsForStage());

        stage.setSkippable(skippable);

        long stageId = request.getLastStageId() + 1;
        if (0L == stageId) {
            stageId = 1L;
        }
        stage.setStageId(stageId);
        entity.setStageId(Long.valueOf(stageId));

        Map<String, String> requestParams = new HashMap<String, String>();

        s_commandExecutionHelper.get().addExecutionCommandsToStage(actionContext, stage, requestParams, allowRetry);

        request.addStages(Collections.singletonList(stage));
    }

    private void makeServerSideStage(UpgradeContext context, RequestStageContainer request,
            UpgradeItemEntity entity, ServerSideActionTask task, boolean skippable, boolean allowRtery)
            throws AmbariException {

        Cluster cluster = context.getCluster();

        Map<String, String> commandParams = new HashMap<String, String>();
        commandParams.put(COMMAND_PARAM_CLUSTER_NAME, cluster.getClusterName());
        commandParams.put(COMMAND_PARAM_VERSION, context.getVersion());
        commandParams.put(COMMAND_PARAM_DIRECTION, context.getDirection().name().toLowerCase());

        String itemDetail = entity.getText();
        String stageText = StringUtils.abbreviate(entity.getText(), 255);

        switch (task.getType()) {
        case MANUAL: {
            ManualTask mt = (ManualTask) task;
            itemDetail = mt.message;
            if (null != mt.summary) {
                stageText = mt.summary;
            }
            entity.setText(itemDetail);

            if (null != mt.structuredOut) {
                commandParams.put(COMMAND_PARAM_STRUCT_OUT, mt.structuredOut);
            }

            break;
        }
        case CONFIGURE: {
            ConfigureTask ct = (ConfigureTask) task;
            Map<String, String> configProperties = ct.getConfigurationProperties(cluster);

            // if the properties are empty it means that the conditions in the
            // task did not pass;
            if (configProperties.isEmpty()) {
                stageText = "No conditions were met for this configuration task.";
                itemDetail = stageText;
            } else {
                commandParams.putAll(configProperties);

                // extract the config type, key and value to use to build the
                // summary and detail
                String configType = configProperties.get(ConfigureTask.PARAMETER_CONFIG_TYPE);
                String key = configProperties.get(ConfigureTask.PARAMETER_KEY);
                String value = configProperties.get(ConfigureTask.PARAMETER_VALUE);

                itemDetail = String.format("Updating config %s/%s to %s", configType, key, value);

                if (null != ct.summary) {
                    stageText = ct.summary;
                } else {
                    stageText = String.format("Updating Config %s", configType);
                }
            }

            entity.setText(itemDetail);
            break;
        }
        default:
            break;
        }

        ActionExecutionContext actionContext = new ActionExecutionContext(cluster.getClusterName(),
                Role.AMBARI_SERVER_ACTION.toString(), Collections.<RequestResourceFilter>emptyList(),
                commandParams);

        actionContext.setTimeout(Short.valueOf((short) -1));
        actionContext.setIgnoreMaintenance(true);

        ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext, cluster);

        Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari",
                cluster.getClusterName(), cluster.getClusterId(), stageText, jsons.getClusterHostInfo(),
                jsons.getCommandParamsForStage(), jsons.getHostParamsForStage());

        stage.setSkippable(skippable);

        long stageId = request.getLastStageId() + 1;
        if (0L == stageId) {
            stageId = 1L;
        }
        stage.setStageId(stageId);
        entity.setStageId(Long.valueOf(stageId));

        // !!! hack hack hack
        String host = cluster.getAllHostsDesiredConfigs().keySet().iterator().next();

        stage.addServerActionCommand(task.getImplementationClass(), getManagementController().getAuthName(),
                Role.AMBARI_SERVER_ACTION, RoleCommand.EXECUTE, cluster.getClusterName(), host,
                new ServiceComponentHostServerActionEvent(StageUtils.getHostName(), System.currentTimeMillis()),
                commandParams, itemDetail, null, Integer.valueOf(1200), allowRtery);

        request.addStages(Collections.singletonList(stage));
    }
}