http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java index c00e64b..bf7647e 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java @@ -90,6 +90,7 @@ 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.ConfigUpgradePack; import org.apache.ambari.server.state.stack.PrereqCheckStatus; import org.apache.ambari.server.state.stack.UpgradePack; import org.apache.ambari.server.state.stack.upgrade.ConfigureTask; @@ -100,6 +101,8 @@ 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.stack.upgrade.UpdateStackGrouping; +import org.apache.ambari.server.state.stack.upgrade.UpgradeType; import org.apache.ambari.server.state.svccomphost.ServiceComponentHostServerActionEvent; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; @@ -117,6 +120,8 @@ 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_TYPE = "Upgrade/type"; + protected static final String UPGRADE_PACK = "Upgrade/pack"; protected static final String UPGRADE_REQUEST_ID = "Upgrade/request_id"; protected static final String UPGRADE_FROM_VERSION = "Upgrade/from_version"; protected static final String UPGRADE_TO_VERSION = "Upgrade/to_version"; @@ -156,6 +161,8 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider 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"; + // TODO AMBARI-12698, change this variable name since it is no longer always a restart. Possible values are rolling_upgrade or nonrolling_upgrade + // This will involve changing Script.py 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"; @@ -222,6 +229,8 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider // properties PROPERTY_IDS.add(UPGRADE_CLUSTER_NAME); PROPERTY_IDS.add(UPGRADE_VERSION); + PROPERTY_IDS.add(UPGRADE_TYPE); + PROPERTY_IDS.add(UPGRADE_PACK); PROPERTY_IDS.add(UPGRADE_REQUEST_ID); PROPERTY_IDS.add(UPGRADE_FROM_VERSION); PROPERTY_IDS.add(UPGRADE_TO_VERSION); @@ -443,6 +452,8 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider ResourceImpl resource = new ResourceImpl(Resource.Type.Upgrade); setResourceProperty(resource, UPGRADE_CLUSTER_NAME, clusterName, requestedIds); + setResourceProperty(resource, UPGRADE_TYPE, entity.getUpgradeType().toString(), requestedIds); + setResourceProperty(resource, UPGRADE_PACK, entity.getUpgradePackage(), 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); @@ -467,6 +478,16 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider boolean skipPrereqChecks = Boolean.parseBoolean((String) requestMap.get(UPGRADE_SKIP_PREREQUISITE_CHECKS)); boolean failOnCheckWarnings = Boolean.parseBoolean((String) requestMap.get(UPGRADE_FAIL_ON_CHECK_WARNINGS)); + /** + * For the unit tests tests, there are multiple upgrade packs for the same type, so + * allow picking one of them. In prod, this is empty. + */ + String preferredUpgradePackName = (String) requestMap.get(UPGRADE_PACK); + + // Default to ROLLING upgrade, but attempt to read from properties. + final UpgradeType upgradeType = requestMap.containsKey(UPGRADE_TYPE) ? + UpgradeType.valueOf((String) requestMap.get(UPGRADE_TYPE)) : UpgradeType.ROLLING; + if (null == clusterName) { throw new AmbariException(String.format("%s is required", UPGRADE_CLUSTER_NAME)); } @@ -475,6 +496,9 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider throw new AmbariException(String.format("%s is required", UPGRADE_VERSION)); } + return s_upgradeHelper.suggestUpgradePack(clusterName, versionForUpgradePack, version, direction, upgradeType); + // TODO AMBARI-12698, reconcile these changes. + /* Cluster cluster = getManagementController().getClusters().getCluster(clusterName); // !!! find upgrade packs based on current stack. This is where to upgrade @@ -494,26 +518,33 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider } Map<String, UpgradePack> packs = s_metaProvider.get().getUpgradePacks(stack.getStackName(), - stack.getStackVersion()); + stack.getStackVersion()); - UpgradePack up = packs.get(versionEntity.getUpgradePackage()); + UpgradePack pack = null; + if (preferredUpgradePackName != null && !preferredUpgradePackName.isEmpty() && packs.containsKey(preferredUpgradePackName)) { + pack = packs.get(preferredUpgradePackName); + } - if (null == up) { + if (null == pack) { // !!! in case there is an upgrade pack that doesn't match the name String repoStackId = versionEntity.getStackId().getStackId(); for (UpgradePack upgradePack : packs.values()) { - if (null != upgradePack.getTargetStack() - && upgradePack.getTargetStack().equals(repoStackId)) { - up = upgradePack; - break; + if (null != upgradePack.getTargetStack() && upgradePack.getTargetStack().equals(repoStackId) && upgradeType == upgradePack.getType()) { + if (null == pack) { + pack = upgradePack; + } else { + throw new AmbariException( + String.format("Unable to perform %s. Found multiple upgrade packs for type %s and target version %s", + direction.getText(false), upgradeType.toString(), repoVersion)); + } } } } - if (null == up) { + if (null == pack) { throw new AmbariException( - String.format("Unable to perform %s. Could not locate upgrade pack %s for version %s", - direction.getText(false), versionEntity.getUpgradePackage(), repoVersion)); + String.format("Unable to perform %s. Could not locate %s upgrade pack for version %s", + direction.getText(false), upgradeType.toString(), repoVersion)); } // Validate there isn't an direction == upgrade/downgrade already in progress. @@ -572,7 +603,8 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider } } - return up; + return pack; + */ } /** @@ -648,7 +680,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider } UpgradeContext ctx = new UpgradeContext(resolver, sourceStackId, targetStackId, version, - direction); + direction, pack.getType()); if (direction.isDowngrade()) { if (requestMap.containsKey(UPGRADE_FROM_VERSION)) { @@ -688,9 +720,39 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider List<UpgradeGroupEntity> groupEntities = new ArrayList<UpgradeGroupEntity>(); RequestStageContainer req = createRequest(direction, version); - // desired configs must be set before creating stages because the config tag - // names are read and set on the command for filling in later - processConfigurations(targetStackId.getStackName(), cluster, version, direction, pack); + /** + During a Rolling Upgrade, change the desired Stack Id if jumping across + major stack versions (e.g., HDP 2.2 -> 2.3), and then set config changes + so they are applied on the newer stack. + + During a {@link UpgradeType.NON_ROLLING} upgrade, the stack is applied during the middle of the upgrade (after + stopping all services), and the configs are applied immediately before starting the services. + The Upgrade Pack is responsible for calling {@link org.apache.ambari.server.serveraction.upgrades.UpdateDesiredStackAction} + at the appropriate moment during the orchestration. + **/ + if (pack.getType() == UpgradeType.ROLLING) { + // Desired configs must be set before creating stages because the config tag + // names are read and set on the command for filling in later + applyStackAndProcessConfigurations(targetStackId.getStackName(), cluster, version, direction, pack); + } + + // Resolve or build a proper config upgrade pack + List<UpgradePack.IntermediateStack> intermediateStacks = pack.getIntermediateStacks(); + ConfigUpgradePack configUpgradePack; + if (intermediateStacks == null || intermediateStacks.isEmpty()) { // No intermediate stacks + configUpgradePack = s_metaProvider.get().getConfigUpgradePack( + targetStackId.getStackName(), targetStackId.getStackVersion()); + } else { + // For cross-stack upgrade, follow all major stacks and merge a new config upgrade pack from all + // target stacks involved into upgrade + ArrayList<ConfigUpgradePack> intermediateConfigUpgradePacks = new ArrayList<>(); + for (UpgradePack.IntermediateStack intermediateStack : intermediateStacks) { + ConfigUpgradePack intermediateConfigUpgradePack = s_metaProvider.get().getConfigUpgradePack( + targetStackId.getStackName(), intermediateStack.version); + intermediateConfigUpgradePacks.add(intermediateConfigUpgradePack); + } + configUpgradePack = ConfigUpgradePack.merge(intermediateConfigUpgradePacks); + } for (UpgradeGroupHolder group : groups) { UpgradeGroupEntity groupEntity = new UpgradeGroupEntity(); @@ -713,11 +775,17 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider itemEntity.setTasks(wrapper.getTasksJson()); itemEntity.setHosts(wrapper.getHostsJson()); itemEntities.add(itemEntity); + + // At this point, need to change the effective Stack Id so that subsequent tasks run on the newer value. + // TODO AMBARI-12698, check if this works during a Stop-the-World Downgrade. + if (UpdateStackGrouping.class.equals(group.groupClass)) { + ctx.setEffectiveStackId(ctx.getTargetStackId()); + } injectVariables(configHelper, cluster, itemEntity); makeServerSideStage(ctx, req, itemEntity, (ServerSideActionTask) task, skippable, - allowRetry); + allowRetry, configUpgradePack); } } } else { @@ -742,8 +810,10 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider entity.setFromVersion(cluster.getCurrentClusterVersion().getRepositoryVersion().getVersion()); entity.setToVersion(version); entity.setUpgradeGroups(groupEntities); - entity.setClusterId(Long.valueOf(cluster.getClusterId())); + entity.setClusterId(cluster.getClusterId()); entity.setDirection(direction); + entity.setUpgradePackage(pack.getName()); + entity.setUpgradeType(pack.getType()); req.getRequestStatusResponse(); @@ -790,7 +860,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider * which services are effected. * @throws AmbariException */ - void processConfigurations(String stackName, Cluster cluster, String version, Direction direction, UpgradePack upgradePack) + void applyStackAndProcessConfigurations(String stackName, Cluster cluster, String version, Direction direction, UpgradePack upgradePack) throws AmbariException { RepositoryVersionEntity targetRve = s_repoVersionDAO.findByStackNameAndVersion(stackName, version); if (null == targetRve) { @@ -822,6 +892,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider Map<String, Map<String, String>> newConfigurationsByType = null; ConfigHelper configHelper = getManagementController().getConfigHelper(); + // TODO AMBARI-12698, handle jumping across several stacks if (direction == Direction.UPGRADE) { // populate a map of default configurations for the old stack (this is // used when determining if a property has been customized and should be @@ -890,7 +961,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider continue; } - // NPE sanity, althought shouldn't even happen since we are iterating + // NPE sanity, although shouldn't even happen since we are iterating // over the desired configs to start with Config currentClusterConfig = cluster.getDesiredConfigByType(configurationType); if (null == currentClusterConfig) { @@ -977,8 +1048,10 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider throws AmbariException { switch (wrapper.getType()) { + case START: + case STOP: case RESTART: - makeRestartStage(context, request, entity, wrapper, skippable, allowRetry); + makeCommandStage(context, request, entity, wrapper, skippable, allowRetry); break; case RU_TASKS: makeActionStage(context, request, entity, wrapper, skippable, allowRetry); @@ -1018,7 +1091,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider // service, it is necessary to set the // service_package_folder and hooks_folder params. AmbariMetaInfo ambariMetaInfo = s_metaProvider.get(); - StackId stackId = cluster.getDesiredStackVersion(); + StackId stackId = context.getEffectiveStackId(); StackInfo stackInfo = ambariMetaInfo.getStack(stackId.getStackName(), stackId.getStackVersion()); @@ -1041,7 +1114,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider actionContext.setAutoSkipFailures(context.isComponentFailureAutoSkipped()); ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext, - cluster); + cluster, context.getEffectiveStackId()); Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari", cluster.getClusterName(), cluster.getClusterId(), entity.getText(), @@ -1070,7 +1143,17 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider request.addStages(Collections.singletonList(stage)); } - private void makeRestartStage(UpgradeContext context, RequestStageContainer request, + /** + * Used to create a stage for restart, start, or stop. + * @param context Upgrade Context + * @param request Container for stage + * @param entity Upgrade Item + * @param wrapper Stage + * @param skippable Whether the item can be skipped + * @param allowRetry Whether the item is allowed to be retried + * @throws AmbariException + */ + private void makeCommandStage(UpgradeContext context, RequestStageContainer request, UpgradeItemEntity entity, StageWrapper wrapper, boolean skippable, boolean allowRetry) throws AmbariException { @@ -1084,23 +1167,43 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider new ArrayList<String>(tw.getHosts()))); } - Map<String, String> restartCommandParams = getNewParameterMap(); - restartCommandParams.put(COMMAND_PARAM_RESTART_TYPE, "rolling_upgrade"); - restartCommandParams.put(COMMAND_PARAM_VERSION, context.getVersion()); - restartCommandParams.put(COMMAND_PARAM_DIRECTION, context.getDirection().name().toLowerCase()); - restartCommandParams.put(COMMAND_PARAM_ORIGINAL_STACK,context.getOriginalStackId().getStackId()); - restartCommandParams.put(COMMAND_PARAM_TARGET_STACK, context.getTargetStackId().getStackId()); - restartCommandParams.put(COMMAND_DOWNGRADE_FROM_VERSION, context.getDowngradeFromVersion()); + String function = null; + switch (wrapper.getType()) { + case START: + case STOP: + case RESTART: + function = wrapper.getType().name(); + break; + default: + function = "UNKNOWN"; + break; + } + + Map<String, String> commandParams = getNewParameterMap(); + + // TODO AMBARI-12698, change COMMAND_PARAM_RESTART_TYPE to something that isn't "RESTART" specific. + if (context.getType() == UpgradeType.ROLLING) { + commandParams.put(COMMAND_PARAM_RESTART_TYPE, "rolling_upgrade"); + } + if (context.getType() == UpgradeType.NON_ROLLING) { + commandParams.put(COMMAND_PARAM_RESTART_TYPE, "nonrolling_upgrade"); + } + + commandParams.put(COMMAND_PARAM_VERSION, context.getVersion()); + commandParams.put(COMMAND_PARAM_DIRECTION, context.getDirection().name().toLowerCase()); + commandParams.put(COMMAND_PARAM_ORIGINAL_STACK, context.getOriginalStackId().getStackId()); + commandParams.put(COMMAND_PARAM_TARGET_STACK, context.getTargetStackId().getStackId()); + commandParams.put(COMMAND_DOWNGRADE_FROM_VERSION, context.getDowngradeFromVersion()); ActionExecutionContext actionContext = new ActionExecutionContext(cluster.getClusterName(), - "RESTART", filters, restartCommandParams); + function, filters, commandParams); actionContext.setTimeout(Short.valueOf(s_configuration.getDefaultAgentTaskTimeout(false))); actionContext.setIgnoreMaintenance(true); actionContext.setRetryAllowed(allowRetry); actionContext.setAutoSkipFailures(context.isComponentFailureAutoSkipped()); ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext, - cluster); + cluster, context.getEffectiveStackId()); Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari", cluster.getClusterName(), cluster.getClusterId(), entity.getText(), @@ -1118,7 +1221,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider entity.setStageId(Long.valueOf(stageId)); Map<String, String> requestParams = new HashMap<String, String>(); - requestParams.put("command", "RESTART"); + requestParams.put("command", function); s_commandExecutionHelper.get().addExecutionCommandsToStage(actionContext, stage, requestParams); @@ -1153,7 +1256,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider actionContext.setAutoSkipFailures(context.isServiceCheckFailureAutoSkipped()); ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext, - cluster); + cluster, context.getEffectiveStackId()); Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari", cluster.getClusterName(), cluster.getClusterId(), entity.getText(), @@ -1176,8 +1279,22 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider request.addStages(Collections.singletonList(stage)); } + /** + * Creates a stage consisting of server side actions + * @param context upgrade context + * @param request upgrade request + * @param entity a single of upgrade + * @param task server-side task (if any) + * @param skippable if user can skip stage on failure + * @param allowRetry if user can retry running stage on failure + * @param configUpgradePack a runtime-generated config upgrade pack that + * contains all config change definitions from all stacks involved into + * upgrade + * @throws AmbariException + */ private void makeServerSideStage(UpgradeContext context, RequestStageContainer request, - UpgradeItemEntity entity, ServerSideActionTask task, boolean skippable, boolean allowRetry) + UpgradeItemEntity entity, ServerSideActionTask task, boolean skippable, boolean allowRetry, + ConfigUpgradePack configUpgradePack) throws AmbariException { Cluster cluster = context.getCluster(); @@ -1225,7 +1342,8 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider } case CONFIGURE: { ConfigureTask ct = (ConfigureTask) task; - Map<String, String> configurationChanges = ct.getConfigurationChanges(cluster); + Map<String, String> configurationChanges = + ct.getConfigurationChanges(cluster, configUpgradePack); // add all configuration changes to the command params commandParams.putAll(configurationChanges); @@ -1262,7 +1380,7 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider actionContext.setAutoSkipFailures(context.isComponentFailureAutoSkipped()); ExecuteCommandJson jsons = s_commandExecutionHelper.get().getCommandJson(actionContext, - cluster); + cluster, context.getEffectiveStackId()); Stage stage = s_stageFactory.get().createNew(request.getId().longValue(), "/tmp/ambari", cluster.getClusterName(), cluster.getClusterId(), stageText, jsons.getClusterHostInfo(),
http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/metadata/ActionMetadata.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/metadata/ActionMetadata.java b/ambari-server/src/main/java/org/apache/ambari/server/metadata/ActionMetadata.java index e821827..f5642a0 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/metadata/ActionMetadata.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/metadata/ActionMetadata.java @@ -58,8 +58,10 @@ public class ActionMetadata { private void fillHostComponentCommands() { //Standart commands for any host component - // TODO: Add START/STOP/INSTALL commands defaultHostComponentCommands.add("RESTART"); + defaultHostComponentCommands.add("START"); + defaultHostComponentCommands.add("STOP"); + defaultHostComponentCommands.add("INSTALL"); defaultHostComponentCommands.add("CONFIGURE"); } http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterVersionDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterVersionDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterVersionDAO.java index d3326b1..8d4c5ee 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterVersionDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ClusterVersionDAO.java @@ -23,8 +23,11 @@ import javax.persistence.NoResultException; import javax.persistence.NonUniqueResultException; import javax.persistence.TypedQuery; +import com.google.inject.persist.Transactional; import org.apache.ambari.server.orm.RequiresSession; +import org.apache.ambari.server.orm.entities.ClusterEntity; import org.apache.ambari.server.orm.entities.ClusterVersionEntity; +import org.apache.ambari.server.orm.entities.RepositoryVersionEntity; import org.apache.ambari.server.state.RepositoryVersionState; import org.apache.ambari.server.state.StackId; @@ -153,4 +156,24 @@ public class ClusterVersionDAO extends CrudDAO<ClusterVersionEntity, Long>{ return daoUtils.selectList(query); } + + /** + * Construct a Cluster Version and return it. This is primarily used to be able to construct the object and mock + * the function call. + * @param cluster Cluster + * @param repositoryVersion Repository Version + * @param state Initial State + * @param startTime Start Time + * @param endTime End Time + * @param userName Username, such as "admin" + * @return Return new ClusterVersion object. + */ + @Transactional + public ClusterVersionEntity create(ClusterEntity cluster, RepositoryVersionEntity repositoryVersion, + RepositoryVersionState state, long startTime, long endTime, String userName) { + ClusterVersionEntity clusterVersionEntity = new ClusterVersionEntity(cluster, + repositoryVersion, state, startTime, endTime, userName); + this.create(clusterVersionEntity); + return clusterVersionEntity; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/CrudDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/CrudDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/CrudDAO.java index 4382f59..ed0a931 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/CrudDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/CrudDAO.java @@ -73,6 +73,21 @@ public class CrudDAO<E, K> { } /** + * Retrieves the maximum ID from the entities. + * + * @param idColName name of the column that corresponds to the ID. + * @return maximum ID, or 0 if none exist. + */ + @RequiresSession + public Long findMaxId(String idColName) { + final TypedQuery<Long> query = entityManagerProvider.get().createQuery("SELECT MAX(entity." + idColName + ") FROM " + + entityClass.getSimpleName() + " entity", Long.class); + // May be null if no results. + Long result = daoUtils.selectOne(query); + return result == null ? 0 : result; + } + + /** * Creates entity. * * @param entity entity to create http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java index a2ff211..ad617af 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostVersionDAO.java @@ -43,21 +43,17 @@ import com.google.inject.persist.Transactional; * {@link org.apache.ambari.server.state.RepositoryVersionState#UPGRADING}. */ @Singleton -public class HostVersionDAO { +public class HostVersionDAO extends CrudDAO<HostVersionEntity, Long> { @Inject Provider<EntityManager> entityManagerProvider; @Inject DaoUtils daoUtils; /** - * Get the object with the given id. - * - * @param id Primary key id - * @return Return the object with the given primary key + * Constructor. */ - @RequiresSession - public HostVersionEntity findByPK(long id) { - return entityManagerProvider.get().find(HostVersionEntity.class, id); + public HostVersionDAO() { + super(HostVersionEntity.class); } /** @@ -189,31 +185,6 @@ public class HostVersionDAO { return daoUtils.selectSingle(query); } - @RequiresSession - public List<HostVersionEntity> findAll() { - return daoUtils.selectAll(entityManagerProvider.get(), HostVersionEntity.class); - } - - @Transactional - public void refresh(HostVersionEntity hostVersionEntity) { - entityManagerProvider.get().refresh(hostVersionEntity); - } - - @Transactional - public void create(HostVersionEntity hostVersionEntity) { - entityManagerProvider.get().persist(hostVersionEntity); - } - - @Transactional - public HostVersionEntity merge(HostVersionEntity hostVersionEntity) { - return entityManagerProvider.get().merge(hostVersionEntity); - } - - @Transactional - public void remove(HostVersionEntity hostVersionEntity) { - entityManagerProvider.get().remove(merge(hostVersionEntity)); - } - @Transactional public void removeByHostName(String hostName) { Collection<HostVersionEntity> hostVersions = this.findByHost(hostName); @@ -221,9 +192,4 @@ public class HostVersionDAO { this.remove(hostVersion); } } - - @Transactional - public void removeByPK(long id) { - remove(findByPK(id)); - } } http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java index 4ac1314..9f5f6f1 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/RepositoryVersionDAO.java @@ -129,15 +129,13 @@ public class RepositoryVersionDAO extends CrudDAO<RepositoryVersionEntity, Long> * @param stackEntity Stack entity. * @param version Stack version, e.g., 2.2 or 2.2.0.1-885 * @param displayName Unique display name - * @param upgradePack Optional upgrade pack, e.g, upgrade-2.2 * @param operatingSystems JSON structure of repository URLs for each OS * @return Returns the object created if successful, and throws an exception otherwise. * @throws AmbariException */ @Transactional public RepositoryVersionEntity create(StackEntity stackEntity, - String version, String displayName, String upgradePack, - String operatingSystems) throws AmbariException { + String version, String displayName, String operatingSystems) throws AmbariException { if (stackEntity == null || version == null || version.isEmpty() || displayName == null || displayName.isEmpty()) { @@ -164,7 +162,7 @@ public class RepositoryVersionDAO extends CrudDAO<RepositoryVersionEntity, Long> } RepositoryVersionEntity newEntity = new RepositoryVersionEntity( - stackEntity, version, displayName, upgradePack, operatingSystems); + stackEntity, version, displayName, operatingSystems); this.create(newEntity); return newEntity; } http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UpgradeDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UpgradeDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UpgradeDAO.java index bc0652c..06f6ac1 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UpgradeDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/UpgradeDAO.java @@ -48,6 +48,18 @@ public class UpgradeDAO { private DaoUtils daoUtils; /** + * Get all items. + * @return List of all of the UpgradeEntity items. + */ + @RequiresSession + public List<UpgradeEntity> findAll() { + TypedQuery<UpgradeEntity> query = entityManagerProvider.get().createNamedQuery( + "UpgradeEntity.findAll", UpgradeEntity.class); + + return daoUtils.selectList(query); + } + + /** * @param clusterId the cluster id * @return the list of upgrades initiated for the cluster */ @@ -157,8 +169,7 @@ public class UpgradeDAO { } /** - * @param requestId the request id - * @param stageId the stage id + * @param clusterId the cluster id * @return the upgrade entity, or {@code null} if not found */ @RequiresSession @@ -174,4 +185,8 @@ public class UpgradeDAO { return daoUtils.selectSingle(query); } + @Transactional + public UpgradeEntity merge(UpgradeEntity upgradeEntity) { + return entityManagerProvider.get().merge(upgradeEntity); + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java index 0fb2f10..16b7c1c 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RepositoryVersionEntity.java @@ -90,9 +90,6 @@ public class RepositoryVersionEntity { @Column(name = "display_name") private String displayName; - @Column(name = "upgrade_package") - private String upgradePackage; - @Lob @Column(name = "repositories") private String operatingSystems; @@ -110,11 +107,10 @@ public class RepositoryVersionEntity { } public RepositoryVersionEntity(StackEntity stack, String version, - String displayName, String upgradePackage, String operatingSystems) { + String displayName, String operatingSystems) { this.stack = stack; this.version = version; this.displayName = displayName; - this.upgradePackage = upgradePackage; this.operatingSystems = operatingSystems; } @@ -161,14 +157,6 @@ public class RepositoryVersionEntity { this.displayName = displayName; } - public String getUpgradePackage() { - return upgradePackage; - } - - public void setUpgradePackage(String upgradePackage) { - this.upgradePackage = upgradePackage; - } - public String getOperatingSystemsJson() { return operatingSystems; } @@ -233,9 +221,6 @@ public class RepositoryVersionEntity { if (displayName != null ? !displayName.equals(that.displayName) : that.displayName != null) { return false; } - if (upgradePackage != null ? !upgradePackage.equals(that.upgradePackage) : that.upgradePackage != null) { - return false; - } if (operatingSystems != null ? !operatingSystems.equals(that.operatingSystems) : that.operatingSystems != null) { return false; } @@ -249,7 +234,6 @@ public class RepositoryVersionEntity { result = 31 * result + (stack != null ? stack.hashCode() : 0); result = 31 * result + (version != null ? version.hashCode() : 0); result = 31 * result + (displayName != null ? displayName.hashCode() : 0); - result = 31 * result + (upgradePackage != null ? upgradePackage.hashCode() : 0); result = 31 * result + (operatingSystems != null ? operatingSystems.hashCode() : 0); return result; } http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeEntity.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeEntity.java index 802ea03..ad9073a 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/UpgradeEntity.java @@ -34,6 +34,7 @@ import javax.persistence.Table; import javax.persistence.TableGenerator; import org.apache.ambari.server.state.stack.upgrade.Direction; +import org.apache.ambari.server.state.stack.upgrade.UpgradeType; /** * Models the data representation of an upgrade @@ -44,6 +45,8 @@ import org.apache.ambari.server.state.stack.upgrade.Direction; table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "sequence_value", pkColumnValue = "upgrade_id_seq", initialValue = 0) @NamedQueries({ + @NamedQuery(name = "UpgradeEntity.findAll", + query = "SELECT u FROM UpgradeEntity u"), @NamedQuery(name = "UpgradeEntity.findAllForCluster", query = "SELECT u FROM UpgradeEntity u WHERE u.clusterId = :clusterId"), @NamedQuery(name = "UpgradeEntity.findUpgrade", @@ -74,6 +77,13 @@ public class UpgradeEntity { @Enumerated(value = EnumType.STRING) private Direction direction = Direction.UPGRADE; + @Column(name="upgrade_package", nullable = false) + private String upgradePackage; + + @Column(name="upgrade_type", nullable = false) + @Enumerated(value = EnumType.STRING) + private UpgradeType upgradeType; + @OneToMany(mappedBy = "upgradeEntity", cascade = { CascadeType.ALL }) private List<UpgradeGroupEntity> upgradeGroupEntities; @@ -179,5 +189,84 @@ public class UpgradeEntity { this.direction = direction; } + /** + * @return the upgrade type, such as rolling or non_rolling + */ + public UpgradeType getUpgradeType() { + return upgradeType; + } + + /** + * @param upgradeType the upgrade type to set + */ + public void setUpgradeType(UpgradeType upgradeType) { + this.upgradeType = upgradeType; + } + + /** + * @return the upgrade package name, without the extension. + */ + public String getUpgradePackage() { + return upgradePackage; + } + + /** + * @param upgradePackage the upgrade pack to set + */ + public void setUpgradePackage(String upgradePackage) { + this.upgradePackage = upgradePackage; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + UpgradeEntity that = (UpgradeEntity) o; + + if (upgradeId != null ? !upgradeId.equals(that.upgradeId) : that.upgradeId != null) { + return false; + } + if (clusterId != null ? !clusterId.equals(that.clusterId) : that.clusterId != null) { + return false; + } + if (requestId != null ? !requestId.equals(that.requestId) : that.requestId != null) { + return false; + } + if (fromVersion != null ? !fromVersion.equals(that.fromVersion) : that.fromVersion != null) { + return false; + } + if (toVersion != null ? !toVersion.equals(that.toVersion) : that.toVersion != null) { + return false; + } + if (direction != null ? !direction.equals(that.direction) : that.direction != null) { + return false; + } + if (upgradeType != null ? !upgradeType.equals(that.upgradeType) : that.upgradeType != null) { + return false; + } + if (upgradePackage != null ? !upgradePackage.equals(that.upgradePackage) : that.upgradePackage != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = upgradeId != null ? upgradeId.hashCode() : 0; + result = 31 * result + (clusterId != null ? clusterId.hashCode() : 0); + result = 31 * result + (requestId != null ? requestId.hashCode() : 0); + result = 31 * result + (fromVersion != null ? fromVersion.hashCode() : 0); + result = 31 * result + (toVersion != null ? toVersion.hashCode() : 0); + result = 31 * result + (direction != null ? direction.hashCode() : 0); + result = 31 * result + (upgradeType != null ? upgradeType.hashCode() : 0); + result = 31 * result + (upgradePackage != null ? upgradePackage.hashCode() : 0); + return result; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/ConfigureAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/ConfigureAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/ConfigureAction.java index c717582..ef21a2a 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/ConfigureAction.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/ConfigureAction.java @@ -46,7 +46,10 @@ import org.apache.ambari.server.state.DesiredConfig; import org.apache.ambari.server.state.PropertyInfo; import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.state.stack.upgrade.ConfigureTask; -import org.apache.ambari.server.state.stack.upgrade.ConfigureTask.ConfigurationKeyValue; +import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.ConfigurationKeyValue; +import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Transfer; +import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Replace; +import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition.Masked; import org.apache.commons.lang.StringUtils; import com.google.gson.Gson; @@ -176,27 +179,27 @@ public class ConfigureAction extends AbstractServerAction { String configType = commandParameters.get(ConfigureTask.PARAMETER_CONFIG_TYPE); // extract transfers - List<ConfigureTask.ConfigurationKeyValue> keyValuePairs = Collections.emptyList(); + List<ConfigurationKeyValue> keyValuePairs = Collections.emptyList(); String keyValuePairJson = commandParameters.get(ConfigureTask.PARAMETER_KEY_VALUE_PAIRS); if (null != keyValuePairJson) { keyValuePairs = m_gson.fromJson( - keyValuePairJson, new TypeToken<List<ConfigureTask.ConfigurationKeyValue>>(){}.getType()); + keyValuePairJson, new TypeToken<List<ConfigurationKeyValue>>(){}.getType()); } // extract transfers - List<ConfigureTask.Transfer> transfers = Collections.emptyList(); + List<Transfer> transfers = Collections.emptyList(); String transferJson = commandParameters.get(ConfigureTask.PARAMETER_TRANSFERS); if (null != transferJson) { transfers = m_gson.fromJson( - transferJson, new TypeToken<List<ConfigureTask.Transfer>>(){}.getType()); + transferJson, new TypeToken<List<Transfer>>(){}.getType()); } // extract replacements - List<ConfigureTask.Replace> replacements = Collections.emptyList(); + List<Replace> replacements = Collections.emptyList(); String replaceJson = commandParameters.get(ConfigureTask.PARAMETER_REPLACEMENTS); if (null != replaceJson) { replacements = m_gson.fromJson( - replaceJson, new TypeToken<List<ConfigureTask.Replace>>(){}.getType()); + replaceJson, new TypeToken<List<Replace>>(){}.getType()); } // if there is nothing to do, then skip the task @@ -240,7 +243,7 @@ public class ConfigureAction extends AbstractServerAction { // !!! do transfers first before setting defined values StringBuilder outputBuffer = new StringBuilder(250); - for (ConfigureTask.Transfer transfer : transfers) { + for (Transfer transfer : transfers) { switch (transfer.operation) { case COPY: String valueToCopy = null; @@ -400,7 +403,7 @@ public class ConfigureAction extends AbstractServerAction { } // !!! string replacements happen only on the new values. - for (ConfigureTask.Replace replacement : replacements) { + for (Replace replacement : replacements) { if (newValues.containsKey(replacement.key)) { String toReplace = newValues.get(replacement.key); @@ -534,7 +537,7 @@ public class ConfigureAction extends AbstractServerAction { return result; } - private static String mask(ConfigureTask.Masked mask, String value) { + private static String mask(Masked mask, String value) { if (mask.mask) { return StringUtils.repeat("*", value.length()); } http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredStackAction.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredStackAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredStackAction.java new file mode 100644 index 0000000..b676c9b --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/upgrades/UpdateDesiredStackAction.java @@ -0,0 +1,139 @@ +/** + * 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.serveraction.upgrades; + +import com.google.inject.Inject; +import org.apache.ambari.server.AmbariException; +import org.apache.ambari.server.actionmanager.HostRoleStatus; +import org.apache.ambari.server.agent.CommandReport; +import org.apache.ambari.server.api.services.AmbariMetaInfo; +import org.apache.ambari.server.serveraction.AbstractServerAction; +import org.apache.ambari.server.state.Cluster; +import org.apache.ambari.server.state.Clusters; +import org.apache.ambari.server.state.StackId; +import org.apache.ambari.server.state.StackInfo; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.util.Map; +import java.util.concurrent.ConcurrentMap; + +/** + * Action that represents updating the Desired Stack Id during the middle of a stack upgrade (typically NonRolling). + * In a {@link org.apache.ambari.server.state.stack.upgrade.UpgradeType#NON_ROLLING}, the effective Stack Id is + * actually changed half-way through calculating the Actions, and this serves to update the database to make it + * evident to the user at which point it changed. + */ +public class UpdateDesiredStackAction extends AbstractServerAction { + + /** + * The original "current" stack of the cluster before the upgrade started. + * This is the same regardless of whether the current direction is + * {@link org.apache.ambari.server.state.stack.upgrade.Direction#UPGRADE} or {@link org.apache.ambari.server.state.stack.upgrade.Direction#DOWNGRADE}. + */ + public static final String ORIGINAL_STACK_KEY = "original_stack"; + + /** + * The target upgrade stack before the upgrade started. This is the same + * regardless of whether the current direction is {@link org.apache.ambari.server.state.stack.upgrade.Direction#UPGRADE} or + * {@link org.apache.ambari.server.state.stack.upgrade.Direction#DOWNGRADE}. + */ + public static final String TARGET_STACK_KEY = "target_stack"; + + /** + * The Cluster that this ServerAction implementation is executing on. + */ + @Inject + private Clusters clusters; + + @Inject + private AmbariMetaInfo ambariMetaInfo; + + @Override + public CommandReport execute(ConcurrentMap<String, Object> requestSharedDataContext) + throws AmbariException, InterruptedException { + Map<String, String> commandParams = getExecutionCommand().getCommandParams(); + + StackId originalStackId = new StackId(commandParams.get(ORIGINAL_STACK_KEY)); + StackId targetStackId = new StackId(commandParams.get(TARGET_STACK_KEY)); + String clusterName = getExecutionCommand().getClusterName(); + + return updateDesiredStack(clusterName, originalStackId, targetStackId); + } + + /** + * Set the cluster's Desired Stack Id during an upgrade. + * + * @param clusterName the name of the cluster the action is meant for + * @paran originalStackId the stack Id of the cluster before the upgrade. + * @paran targetStackId the stack Id that was desired for this upgrade. + * @return the command report to return + */ + private CommandReport updateDesiredStack(String clusterName, StackId originalStackId, StackId targetStackId) + throws AmbariException, InterruptedException { + StringBuilder out = new StringBuilder(); + StringBuilder err = new StringBuilder(); + + try { + Cluster cluster = clusters.getCluster(clusterName); + StackId currentClusterStackId = cluster.getCurrentStackVersion(); + + out.append(String.format("Checking if can update the Desired Stack Id to %s. The cluster's current Stack Id is %s\n", targetStackId.getStackId(), currentClusterStackId.getStackId())); + + // Ensure that the target stack id exist + StackInfo desiredClusterStackInfo = ambariMetaInfo.getStack(targetStackId.getStackName(), targetStackId.getStackVersion()); + if (null == desiredClusterStackInfo) { + String message = String.format("Parameter %s has an invalid value: %s. That Stack Id does not exist.\n", + TARGET_STACK_KEY, targetStackId.getStackId()); + err.append(message); + out.append(message); + return createCommandReport(-1, HostRoleStatus.FAILED, "{}", out.toString(), err.toString()); + } + + // Ensure that the current Stack Id coincides with the parameter that the user passed in. + if (!currentClusterStackId.equals(originalStackId)) { + String message = String.format("Parameter %s has invalid value: %s. " + + "The cluster is currently on stack %s, " + currentClusterStackId.getStackId() + + ", yet the parameter to this function indicates a different value.\n", ORIGINAL_STACK_KEY, targetStackId.getStackId(), currentClusterStackId.getStackId()); + err.append(message); + out.append(message); + return createCommandReport(-1, HostRoleStatus.FAILED, "{}", out.toString(), err.toString()); + } + + // Check for a no-op + if (currentClusterStackId.equals(targetStackId)) { + String message = String.format("Success! The cluster's Desired Stack Id was already set to %s\n", targetStackId.getStackId()); + out.append(message); + return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", out.toString(), err.toString()); + } + + cluster.setDesiredStackVersion(targetStackId, true); + String message = String.format("Success! Set cluster's %s Desired Stack Id to %s.\n", clusterName, targetStackId.getStackId()); + out.append(message); + + return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", out.toString(), err.toString()); + } catch (Exception e) { + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw)); + err.append(sw.toString()); + + return createCommandReport(-1, HostRoleStatus.FAILED, "{}", out.toString(), err.toString()); + } + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/stack/ModuleFileUnmarshaller.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/ModuleFileUnmarshaller.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/ModuleFileUnmarshaller.java index aa8e17b..9e2f997 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/ModuleFileUnmarshaller.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/ModuleFileUnmarshaller.java @@ -18,6 +18,7 @@ package org.apache.ambari.server.stack; +import org.apache.ambari.server.state.stack.ConfigUpgradePack; import org.apache.ambari.server.state.stack.ConfigurationXml; import org.apache.ambari.server.state.stack.RepositoryXml; import org.apache.ambari.server.state.stack.ServiceMetainfoXml; @@ -63,12 +64,13 @@ class ModuleFileUnmarshaller { try { // three classes define the top-level element "metainfo", so we need 3 contexts. JAXBContext ctx = JAXBContext.newInstance(StackMetainfoXml.class, RepositoryXml.class, - ConfigurationXml.class, UpgradePack.class); + ConfigurationXml.class, UpgradePack.class, ConfigUpgradePack.class); jaxbContexts.put(StackMetainfoXml.class, ctx); jaxbContexts.put(RepositoryXml.class, ctx); jaxbContexts.put(ConfigurationXml.class, ctx); jaxbContexts.put(UpgradePack.class, ctx); + jaxbContexts.put(ConfigUpgradePack.class, ctx); jaxbContexts.put(ServiceMetainfoXml.class, JAXBContext.newInstance(ServiceMetainfoXml.class)); } catch (JAXBException e) { throw new RuntimeException (e); http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDefinitionDirectory.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDefinitionDirectory.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDefinitionDirectory.java index 8f81b5a..c739211 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDefinitionDirectory.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDefinitionDirectory.java @@ -37,6 +37,8 @@ public abstract class StackDefinitionDirectory { } }; + protected static final String CONFIG_UPGRADE_XML_FILENAME_PREFIX = "config-upgrade.xml"; + /** * underlying directory */ http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java index 89c10c6..515d031 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackDirectory.java @@ -23,6 +23,7 @@ import org.apache.ambari.server.api.services.AmbariMetaInfo; import org.apache.ambari.server.state.stack.RepositoryXml; import org.apache.ambari.server.state.stack.StackMetainfoXml; import org.apache.ambari.server.state.stack.StackRoleCommandOrder; +import org.apache.ambari.server.state.stack.ConfigUpgradePack; import org.apache.ambari.server.state.stack.UpgradePack; import org.apache.commons.io.FilenameUtils; import org.codehaus.jackson.map.ObjectMapper; @@ -95,10 +96,14 @@ public class StackDirectory extends StackDefinitionDirectory { /** * map of upgrade pack name to upgrade pack */ - //todo: should be a collection but upgrade pack doesn't have a name attribute private Map<String, UpgradePack> upgradePacks; /** + * Config delta from prev stack + */ + private ConfigUpgradePack configUpgradePack; + + /** * metainfo file representation */ private StackMetainfoXml metaInfoXml; @@ -255,6 +260,13 @@ public class StackDirectory extends StackDefinitionDirectory { } /** + * @return Config delta from prev stack or null if no config upgrade patches available + */ + public ConfigUpgradePack getConfigUpgradePack() { + return configUpgradePack; + } + + /** * Obtain the object representation of the stack role_command_order.json file * * @return object representation of the stack role_command_order.json file @@ -405,18 +417,35 @@ public class StackDirectory extends StackDefinitionDirectory { * @throws AmbariException if unable to parse stack upgrade file */ private void parseUpgradePacks(Collection<String> subDirs) throws AmbariException { - Map<String, UpgradePack> upgradeMap = new HashMap<String, UpgradePack>(); + Map<String, UpgradePack> upgradeMap = new HashMap<>(); + ConfigUpgradePack configUpgradePack = null; if (subDirs.contains(UPGRADE_PACK_FOLDER_NAME)) { File f = new File(getAbsolutePath() + File.separator + UPGRADE_PACK_FOLDER_NAME); if (f.isDirectory()) { upgradesDir = f.getAbsolutePath(); for (File upgradeFile : f.listFiles(XML_FILENAME_FILTER)) { - try { - upgradeMap.put(FilenameUtils.removeExtension(upgradeFile.getName()), - unmarshaller.unmarshal(UpgradePack.class, upgradeFile)); - } catch (JAXBException e) { - throw new AmbariException("Unable to parse stack upgrade file at location: " + - upgradeFile.getAbsolutePath(), e); + if (upgradeFile.getName().toLowerCase().startsWith(CONFIG_UPGRADE_XML_FILENAME_PREFIX)) { + try { // Parse config upgrade pack + if (configUpgradePack == null) { + configUpgradePack = unmarshaller.unmarshal(ConfigUpgradePack.class, upgradeFile); + } else { // If user messed things up with lower/upper case filenames + throw new AmbariException(String.format("There are multiple files with name like %s" + + upgradeFile.getAbsolutePath())); + } + } catch (JAXBException e) { + throw new AmbariException("Unable to parse stack upgrade file at location: " + + upgradeFile.getAbsolutePath(), e); + } + } else { + try { + String upgradePackName = FilenameUtils.removeExtension(upgradeFile.getName()); + UpgradePack pack = unmarshaller.unmarshal(UpgradePack.class, upgradeFile); + pack.setName(upgradePackName); + upgradeMap.put(upgradePackName, pack); + } catch (JAXBException e) { + throw new AmbariException("Unable to parse stack upgrade file at location: " + + upgradeFile.getAbsolutePath(), e); + } } } } @@ -429,6 +458,13 @@ public class StackDirectory extends StackDefinitionDirectory { if (! upgradeMap.isEmpty()) { upgradePacks = upgradeMap; } + + if (configUpgradePack != null) { + this.configUpgradePack = configUpgradePack; + } else { + LOG.info("Stack '{}' doesn't contain config upgrade pack file", getPath()); + } + } /** http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java index 4fe7ed7..def33f0 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/stack/StackModule.java @@ -22,7 +22,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -422,6 +421,7 @@ public class StackModule extends BaseModule<StackModule, StackInfo> implements V stackInfo.setWidgetsDescriptorFileLocation(stackDirectory.getWidgetsDescriptorFilePath()); stackInfo.setUpgradesFolder(stackDirectory.getUpgradesDir()); stackInfo.setUpgradePacks(stackDirectory.getUpgradePacks()); + stackInfo.setConfigUpgradePack(stackDirectory.getConfigUpgradePack()); stackInfo.setRoleCommandOrder(stackDirectory.getRoleCommandOrder()); populateConfigurationModules(); } http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java index 8e9d092..e3ac3e0 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/StackInfo.java @@ -31,6 +31,7 @@ import java.util.Set; import org.apache.ambari.server.controller.StackVersionResponse; import org.apache.ambari.server.stack.Validable; import org.apache.ambari.server.state.stack.StackRoleCommandOrder; +import org.apache.ambari.server.state.stack.ConfigUpgradePack; import org.apache.ambari.server.state.stack.UpgradePack; public class StackInfo implements Comparable<StackInfo>, Validable{ @@ -67,6 +68,7 @@ public class StackInfo implements Comparable<StackInfo>, Validable{ private List<PropertyInfo> properties; private Map<String, Map<String, Map<String, String>>> configTypes; private Map<String, UpgradePack> upgradePacks; + private ConfigUpgradePack configUpgradePack; private StackRoleCommandOrder roleCommandOrder; private boolean valid = true; @@ -373,23 +375,40 @@ public class StackInfo implements Comparable<StackInfo>, Validable{ } /** + * Obtain all stack upgrade packs. + * + * @return map of upgrade pack name to upgrade pack or {@code null} if no packs + */ + public Map<String, UpgradePack> getUpgradePacks() { + return upgradePacks; + } + + /** * Set upgrade packs. * - * @param upgradePacks map of upgrade packs + * @param upgradePacks map of upgrade packs */ public void setUpgradePacks(Map<String, UpgradePack> upgradePacks) { this.upgradePacks = upgradePacks; } /** - * Obtain all stack upgrade packs. - * - * @return map of upgrade pack name to upgrade pack or {@code null} of no packs + * Get config upgrade pack for stack + * @return config upgrade pack for stack or null if it is + * not defined */ - public Map<String, UpgradePack> getUpgradePacks() { - return upgradePacks; + public ConfigUpgradePack getConfigUpgradePack() { + return configUpgradePack; } + /** + * Set config upgrade pack for stack + * @param configUpgradePack config upgrade pack for stack or null if it is + * not defined + */ + public void setConfigUpgradePack(ConfigUpgradePack configUpgradePack) { + this.configUpgradePack = configUpgradePack; + } @Override public int compareTo(StackInfo o) { http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContext.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContext.java b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContext.java index b10db9e..15559a3 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContext.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeContext.java @@ -25,6 +25,7 @@ import java.util.Map; import org.apache.ambari.server.api.services.AmbariMetaInfo; import org.apache.ambari.server.stack.MasterHostResolver; import org.apache.ambari.server.state.stack.upgrade.Direction; +import org.apache.ambari.server.state.stack.upgrade.UpgradeType; /** * Used to hold various helper objects required to process an upgrade pack. @@ -41,6 +42,14 @@ public class UpgradeContext { private StackId m_originalStackId; /** + * The stack currently used to start/restart services during an upgrade.This is the same + * During a {@link UpgradeType#ROLLING} upgrade, this is always the {@link this.m_targetStackId}, + * During a {@link UpgradeType#NON_ROLLING} upgrade, this is initially the {@link this.m_sourceStackId} while + * stopping services, and then changes to the {@link this.m_targetStackId} when starting services. + */ + private StackId m_effectiveStackId; + + /** * The target upgrade stack before the upgrade started. This is the same * regardless of whether the current direction is {@link Direction#UPGRADE} or * {@link Direction#DOWNGRADE}. @@ -54,6 +63,7 @@ public class UpgradeContext { private Map<String, String> m_serviceNames = new HashMap<String, String>(); private Map<String, String> m_componentNames = new HashMap<String, String>(); private String m_downgradeFromVersion = null; + private UpgradeType m_type = null; /** * {@code true} if slave/client component failures should be automatically @@ -88,15 +98,31 @@ public class UpgradeContext { * the target version to upgrade to * @param direction * the direction for the upgrade + * @param type + * the type of upgrade, either rolling or non_rolling */ public UpgradeContext(MasterHostResolver resolver, StackId sourceStackId, StackId targetStackId, String version, - Direction direction) { + Direction direction, UpgradeType type) { m_version = version; m_originalStackId = sourceStackId; + + switch (type) { + case ROLLING: + m_effectiveStackId = targetStackId; + break; + case NON_ROLLING: + m_effectiveStackId = sourceStackId; + break; + default: + m_effectiveStackId = targetStackId; + break; + } + m_targetStackId = targetStackId; m_direction = direction; m_resolver = resolver; + m_type = type; } /** @@ -121,6 +147,13 @@ public class UpgradeContext { } /** + * @return the type of upgrade. + */ + public UpgradeType getType() { + return m_type; + } + + /** * @return the resolver */ public MasterHostResolver getResolver() { @@ -164,6 +197,21 @@ public class UpgradeContext { } /** + * @return the effectiveStackId that is currently in use. + */ + public StackId getEffectiveStackId() { + return m_effectiveStackId; + } + + /** + * @param effectiveStackId the effectiveStackId to set + */ + public void setEffectiveStackId(StackId effectiveStackId) { + m_effectiveStackId = effectiveStackId; + } + + + /** * @return the targetStackId */ public StackId getTargetStackId() { @@ -237,7 +285,7 @@ public class UpgradeContext { /** * This method returns the non-finalized version we are downgrading from. - * + * * @return version cluster is downgrading from */ public String getDowngradeFromVersion() { @@ -246,11 +294,11 @@ public class UpgradeContext { /** * Set the HDP stack version we are downgrading from. - * + * * @param downgradeFromVersion */ public void setDowngradeFromVersion(String downgradeFromVersion) { - m_downgradeFromVersion = downgradeFromVersion; + this.m_downgradeFromVersion = downgradeFromVersion; } /** http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java index 75c04da..f0b383c 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/UpgradeHelper.java @@ -17,6 +17,7 @@ */ package org.apache.ambari.server.state; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; @@ -42,6 +43,8 @@ import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; import org.apache.ambari.server.controller.utilities.ClusterControllerHelper; import org.apache.ambari.server.controller.utilities.PredicateBuilder; import org.apache.ambari.server.controller.utilities.PropertyHelper; +import org.apache.ambari.server.orm.dao.RepositoryVersionDAO; +import org.apache.ambari.server.orm.entities.RepositoryVersionEntity; import org.apache.ambari.server.stack.HostsType; import org.apache.ambari.server.stack.MasterHostResolver; import org.apache.ambari.server.state.stack.UpgradePack; @@ -49,11 +52,18 @@ import org.apache.ambari.server.state.stack.UpgradePack.ProcessingComponent; import org.apache.ambari.server.state.stack.upgrade.Direction; import org.apache.ambari.server.state.stack.upgrade.Grouping; import org.apache.ambari.server.state.stack.upgrade.ManualTask; +import org.apache.ambari.server.state.stack.upgrade.RestartGrouping; +import org.apache.ambari.server.state.stack.upgrade.RestartTask; import org.apache.ambari.server.state.stack.upgrade.StageWrapper; import org.apache.ambari.server.state.stack.upgrade.StageWrapperBuilder; +import org.apache.ambari.server.state.stack.upgrade.StartGrouping; +import org.apache.ambari.server.state.stack.upgrade.StartTask; +import org.apache.ambari.server.state.stack.upgrade.StopGrouping; +import org.apache.ambari.server.state.stack.upgrade.StopTask; import org.apache.ambari.server.state.stack.upgrade.Task; import org.apache.ambari.server.state.stack.upgrade.Task.Type; import org.apache.ambari.server.state.stack.upgrade.TaskWrapper; +import org.apache.ambari.server.state.stack.upgrade.UpgradeType; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -171,6 +181,68 @@ public class UpgradeHelper { @Inject private Provider<AmbariMetaInfo> m_ambariMetaInfo; + @Inject + private Provider<Clusters> clusters; + + @Inject + private Provider<RepositoryVersionDAO> s_repoVersionDAO; + + + /** + * Get right Upgrade Pack, depends on stack, direction and upgrade type information + * @param clusterName The name of the cluster + * @param upgradeFromVersion Current stack version + * @param upgradeToVersion Target stack version + * @param direction {@code Direction} of the upgrade + * @param upgradeType The {@code UpgradeType} + * @return {@code UpgradeType} object + * @throws AmbariException + */ + public UpgradePack suggestUpgradePack(String clusterName, String upgradeFromVersion, String upgradeToVersion, + Direction direction, UpgradeType upgradeType) throws AmbariException { + + // !!! find upgrade packs based on current stack. This is where to upgrade from + Cluster cluster = clusters.get().getCluster(clusterName); + StackId stack = cluster.getCurrentStackVersion(); + + String repoVersion = upgradeToVersion; + + // ToDo: AMBARI-12706. Here we need to check, how this would work with SWU Downgrade + if (direction.isDowngrade() && null != upgradeFromVersion) { + repoVersion = upgradeFromVersion; + } + + RepositoryVersionEntity versionEntity = s_repoVersionDAO.get().findByStackNameAndVersion(stack.getStackName(), repoVersion); + + if (versionEntity == null) { + throw new AmbariException(String.format("Repository version %s was not found", repoVersion)); + } + + Map<String, UpgradePack> packs = m_ambariMetaInfo.get().getUpgradePacks(stack.getStackName(), stack.getStackVersion()); + UpgradePack pack = null; + + String repoStackId = versionEntity.getStackId().getStackId(); + for (UpgradePack upgradePack : packs.values()) { + if (upgradePack.getTargetStack() != null && upgradePack.getTargetStack().equals(repoStackId) && + upgradeType == upgradePack.getType()) { + if (pack == null) { + pack = upgradePack; + } else { + throw new AmbariException( + String.format("Found multiple upgrade packs for type %s and target version %s", + upgradeType.toString(), repoVersion)); + } + } + } + + if (pack == null) { + throw new AmbariException(String.format("No upgrade pack found for type %s and target version %s", + upgradeType.toString(),repoVersion)); + } + + return pack; + } + /** * Generates a list of UpgradeGroupHolder items that are used to execute either @@ -189,14 +261,16 @@ public class UpgradeHelper { Cluster cluster = context.getCluster(); MasterHostResolver mhr = context.getResolver(); + // Note, only a Rolling Upgrade uses processing tasks. Map<String, Map<String, ProcessingComponent>> allTasks = upgradePack.getTasks(); - List<UpgradeGroupHolder> groups = new ArrayList<UpgradeGroupHolder>(); + List<UpgradeGroupHolder> groups = new ArrayList<>(); for (Grouping group : upgradePack.getGroups(context.getDirection())) { UpgradeGroupHolder groupHolder = new UpgradeGroupHolder(); groupHolder.name = group.name; groupHolder.title = group.title; + groupHolder.groupClass = group.getClass(); groupHolder.skippable = group.skippable; groupHolder.allowRetry = group.allowRetry; @@ -205,29 +279,52 @@ public class UpgradeHelper { groupHolder.skippable = true; } + // NonRolling defaults to not performing service checks on a group. + // Of course, a Service Check Group does indeed run them. + if (upgradePack.getType() == UpgradeType.NON_ROLLING) { + group.performServiceCheck = false; + } + StageWrapperBuilder builder = group.getBuilder(); List<UpgradePack.OrderService> services = group.services; - if (context.getDirection().isDowngrade() && !services.isEmpty()) { - List<UpgradePack.OrderService> reverse = new ArrayList<UpgradePack.OrderService>(services); - Collections.reverse(reverse); - services = reverse; + // Rolling Downgrade must reverse the order of services. + if (upgradePack.getType() == UpgradeType.ROLLING) { + if (context.getDirection().isDowngrade() && !services.isEmpty()) { + List<UpgradePack.OrderService> reverse = new ArrayList<>(services); + Collections.reverse(reverse); + services = reverse; + } } // !!! cluster and service checks are empty here for (UpgradePack.OrderService service : services) { - if (!allTasks.containsKey(service.serviceName)) { + if (upgradePack.getType() == UpgradeType.ROLLING && !allTasks.containsKey(service.serviceName)) { continue; } + + // Attempt to get the function of the group, during a NonRolling Upgrade + Task.Type functionName = null; + + if (RestartGrouping.class.isInstance(group)) { + functionName = ((RestartGrouping) group).getFunction(); + } + if (StartGrouping.class.isInstance(group)) { + functionName = ((StartGrouping) group).getFunction(); + } + if (StopGrouping.class.isInstance(group)) { + functionName = ((StopGrouping) group).getFunction(); + } for (String component : service.components) { - if (!allTasks.get(service.serviceName).containsKey(component)) { + if (upgradePack.getType() == UpgradeType.ROLLING && !allTasks.get(service.serviceName).containsKey(component)) { continue; } - + HostsType hostsType = mhr.getMasterAndHosts(service.serviceName, component); + // TODO AMBARI-12698, how does this impact SECONDARY NAMENODE if there's no NameNode HA? if (null == hostsType) { continue; } @@ -237,7 +334,31 @@ public class UpgradeHelper { } Service svc = cluster.getService(service.serviceName); - ProcessingComponent pc = allTasks.get(service.serviceName).get(component); + + ProcessingComponent pc = null; + if (upgradePack.getType() == UpgradeType.ROLLING) { + pc = allTasks.get(service.serviceName).get(component); + } else if (upgradePack.getType() == UpgradeType.NON_ROLLING) { + // Construct a processing task on-the-fly + if (null != functionName) { + pc = new ProcessingComponent(); + pc.name = component; + pc.tasks = new ArrayList<>(); + + if (functionName == Type.START) { + pc.tasks.add(new StartTask()); + } else if (functionName == Type.STOP) { + pc.tasks.add(new StopTask()); + } else if (functionName == Type.RESTART) { + pc.tasks.add(new RestartTask()); + } + } + } + + if (pc == null) { + LOG.error(MessageFormat.format("Couldn't create a processing component for service {0} and component {1}.", service.serviceName, component)); + continue; + } setDisplayNames(context, service.serviceName, component); @@ -246,7 +367,7 @@ public class UpgradeHelper { // !!! revisit if needed if (!hostsType.hosts.isEmpty() && hostsType.master != null && hostsType.secondary != null) { // The order is important, first do the standby, then the active namenode. - LinkedHashSet<String> order = new LinkedHashSet<String>(); + LinkedHashSet<String> order = new LinkedHashSet<>(); order.add(hostsType.secondary); order.add(hostsType.master); @@ -342,7 +463,7 @@ public class UpgradeHelper { String result = source; - List<String> tokens = new ArrayList<String>(5); + List<String> tokens = new ArrayList<>(5); Matcher matcher = PLACEHOLDER_REGEX.matcher(source); while (matcher.find()) { tokens.add(matcher.group(1)); @@ -424,6 +545,9 @@ public class UpgradeHelper { */ public String title; + + public Class<? extends Grouping> groupClass; + /** * Indicate whether retry is allowed for the stages in this group. */ @@ -438,7 +562,7 @@ public class UpgradeHelper { /** * List of stages for the group */ - public List<StageWrapper> items = new ArrayList<StageWrapper>(); + public List<StageWrapper> items = new ArrayList<>(); /** * {@inheritDoc} @@ -521,8 +645,5 @@ public class UpgradeHelper { } catch (AmbariException e) { LOG.debug("Could not get service detail", e); } - - } - } http://git-wip-us.apache.org/repos/asf/ambari/blob/ff8a56af/ambari-server/src/main/java/org/apache/ambari/server/state/stack/ConfigUpgradePack.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/stack/ConfigUpgradePack.java b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/ConfigUpgradePack.java new file mode 100644 index 0000000..f2e2e61 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/stack/ConfigUpgradePack.java @@ -0,0 +1,192 @@ +/** + * 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.state.stack; + +import org.apache.ambari.server.state.stack.upgrade.ConfigUpgradeChangeDefinition; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Represents a pack of changes that should be applied to configs + * when upgrading from a previous stack. In other words, it's a config delta + * from prev stack. + * + * After first call of enumerateConfigChangesByID() method, instance contains + * a cache of data, so it should not be modified in runtime (otherwise + * the cache will become outdated). + */ +@XmlRootElement(name="upgrade-config-changes") +@XmlAccessorType(XmlAccessType.FIELD) +public class ConfigUpgradePack { + + /** + * Defines per-service config changes. + */ + @XmlElementWrapper(name="services") + @XmlElement(name="service") + public List<AffectedService> services; + + /** + * Contains a cached mapping of <change id, change definition>. + */ + private Map<String, ConfigUpgradeChangeDefinition> changesById; + + private static Logger LOG = LoggerFactory.getLogger(ConfigUpgradePack.class); + + /** + * no-arg default constructor for JAXB + */ + public ConfigUpgradePack() { + } + + public ConfigUpgradePack(List<AffectedService> services) { + this.services = services; + } + + /** + * @return a map of <service name, AffectedService>. + */ + public Map<String, AffectedService> getServiceMap() { + Map<String, AffectedService> result = new HashMap<>(); + for (AffectedService service : services) { + result.put(service.name, service); + } + return result; + } + + /** + * @return a map of <change id, change definition>. Map is built once and + * cached + */ + public Map<String, ConfigUpgradeChangeDefinition> enumerateConfigChangesByID() { + if (changesById == null) { + changesById = new HashMap<>(); + for(AffectedService service : services) { + for(AffectedComponent component: service.components) { + for (ConfigUpgradeChangeDefinition changeDefinition : component.changes) { + if (changeDefinition.id == null) { + LOG.warn(String.format("Config upgrade change definition for service %s," + + " component %s has no id", service.name, component.name)); + } else if (changesById.containsKey(changeDefinition.id)) { + LOG.warn("Duplicate config upgrade change definition with ID " + + changeDefinition.id); + } + changesById.put(changeDefinition.id, changeDefinition); + } + } + } + } + return changesById; + } + + /** + * Merges few config upgrade packs into one and returs result. During merge, + * a deep copy of AffectedService and AffectedComponent lists is added to resulting + * config upgrade pack. The only level that is not copied deeply is a list of + * per-component config changes. + * @param cups list of source config upgrade packs + * @return merged config upgrade pack that is a deep copy of source + * config upgrade packs + */ + public static ConfigUpgradePack merge(ArrayList<ConfigUpgradePack> cups) { + // Map <service_name, <component_name, component_changes>> + Map<String, Map<String, AffectedComponent>> mergedServiceMap = new HashMap<>(); + + for (ConfigUpgradePack configUpgradePack : cups) { + for (AffectedService service : configUpgradePack.services) { + if (! mergedServiceMap.containsKey(service.name)) { + mergedServiceMap.put(service.name, new HashMap<String, AffectedComponent>()); + } + Map<String, AffectedComponent> mergedComponentMap = mergedServiceMap.get(service.name); + + for (AffectedComponent component : service.components) { + if (! mergedComponentMap.containsKey(component.name)) { + AffectedComponent mergedComponent = new AffectedComponent(); + mergedComponent.name = component.name; + mergedComponent.changes = new ArrayList<>(); + mergedComponentMap.put(component.name, mergedComponent); + } + AffectedComponent mergedComponent = mergedComponentMap.get(component.name); + mergedComponent.changes.addAll(component.changes); + } + + } + } + // Convert merged maps into new ConfigUpgradePack + ArrayList<AffectedService> mergedServices = new ArrayList<>(); + for (String serviceName : mergedServiceMap.keySet()) { + AffectedService mergedService = new AffectedService(); + Map<String, AffectedComponent> mergedComponentMap = mergedServiceMap.get(serviceName); + mergedService.name = serviceName; + mergedService.components = new ArrayList<>(mergedComponentMap.values()); + mergedServices.add(mergedService); + } + + return new ConfigUpgradePack(mergedServices); + } + + /** + * A service definition in the 'services' element. + */ + public static class AffectedService { + + @XmlAttribute + public String name; + + @XmlElement(name="component") + public List<AffectedComponent> components; + + /** + * @return a map of <component name, AffectedService> + */ + public Map<String, AffectedComponent> getComponentMap() { + Map<String, AffectedComponent> result = new HashMap<>(); + for (AffectedComponent component : components) { + result.put(component.name, component); + } + return result; + } + } + + /** + * A component definition in the 'services/service' path. + */ + public static class AffectedComponent { + + @XmlAttribute + public String name; + + @XmlElementWrapper(name="changes") + @XmlElement(name="definition") + public List<ConfigUpgradeChangeDefinition> changes; + + } +}