Repository: ambari Updated Branches: refs/heads/branch-2.1 49746d8c3 -> ade69a111
AMBARI-13591. RU and EU: Allow set-current to force a version into the db (ncole) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/ade69a11 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/ade69a11 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/ade69a11 Branch: refs/heads/branch-2.1 Commit: ade69a111e9026774ce8cb97f4fe9c6113eed677 Parents: 49746d8 Author: Nate Cole <[email protected]> Authored: Thu Oct 29 16:28:56 2015 -0400 Committer: Nate Cole <[email protected]> Committed: Thu Oct 29 16:29:15 2015 -0400 ---------------------------------------------------------------------- .../ClusterStackVersionResourceProvider.java | 158 +++++++++++------- .../server/orm/dao/ClusterVersionDAO.java | 36 ++++- .../orm/dao/HostComponentDesiredStateDAO.java | 19 ++- .../server/orm/dao/HostComponentStateDAO.java | 28 ++++ .../ambari/server/orm/dao/HostVersionDAO.java | 32 ++++ ambari-server/src/main/python/ambari-server.py | 2 +- .../main/python/ambari_server/serverUpgrade.py | 8 +- ...ClusterStackVersionResourceProviderTest.java | 160 +++++++++++++++++++ .../src/test/python/TestServerUpgrade.py | 55 ++++++- 9 files changed, 427 insertions(+), 71 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/ade69a11/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java index 9a93d24..02a5a1a 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProvider.java @@ -17,10 +17,18 @@ */ package org.apache.ambari.server.controller.internal; -import com.google.gson.Gson; -import com.google.inject.Inject; -import com.google.inject.Injector; -import com.google.inject.Provider; +import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_LOCATION; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.Role; import org.apache.ambari.server.StaticallyInject; @@ -51,11 +59,10 @@ import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; import org.apache.ambari.server.controller.utilities.PropertyHelper; import org.apache.ambari.server.orm.dao.ClusterDAO; import org.apache.ambari.server.orm.dao.ClusterVersionDAO; +import org.apache.ambari.server.orm.dao.HostComponentStateDAO; import org.apache.ambari.server.orm.dao.HostVersionDAO; import org.apache.ambari.server.orm.dao.RepositoryVersionDAO; -import org.apache.ambari.server.orm.entities.ClusterEntity; import org.apache.ambari.server.orm.entities.ClusterVersionEntity; -import org.apache.ambari.server.orm.entities.HostEntity; import org.apache.ambari.server.orm.entities.HostVersionEntity; import org.apache.ambari.server.orm.entities.OperatingSystemEntity; import org.apache.ambari.server.orm.entities.RepositoryEntity; @@ -74,17 +81,11 @@ import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.utils.StageUtils; import org.apache.commons.lang.StringUtils; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_LOCATION; +import com.google.gson.Gson; +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.Provider; +import com.google.inject.persist.Transactional; /** * Resource provider for cluster stack versions resources. @@ -102,6 +103,7 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou protected static final String CLUSTER_STACK_VERSION_HOST_STATES_PROPERTY_ID = PropertyHelper.getPropertyId("ClusterStackVersions", "host_states"); protected static final String CLUSTER_STACK_VERSION_REPOSITORY_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId("ClusterStackVersions", "repository_version"); protected static final String CLUSTER_STACK_VERSION_STAGE_SUCCESS_FACTOR = PropertyHelper.getPropertyId("ClusterStackVersions", "success_factor"); + protected static final String CLUSTER_STACK_VERSION_FORCE = "ClusterStackVersions/force"; protected static final String INSTALL_PACKAGES_ACTION = "install_packages"; protected static final String INSTALL_PACKAGES_FULL_NAME = "Install version"; @@ -141,6 +143,7 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou add(CLUSTER_STACK_VERSION_STATE_PROPERTY_ID); add(CLUSTER_STACK_VERSION_REPOSITORY_VERSION_PROPERTY_ID); add(CLUSTER_STACK_VERSION_STAGE_SUCCESS_FACTOR); + add(CLUSTER_STACK_VERSION_FORCE); } }; @@ -187,6 +190,9 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou @Inject private static Injector injector; + @Inject + private static HostComponentStateDAO hostComponentStateDAO; + /** * We have to include such a hack here, because if we * make finalizeUpgradeAction field static and request injection @@ -575,57 +581,73 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou Cluster cluster = getManagementController().getClusters().getCluster(clName); cluster.setDesiredStackVersion(stackId); - Map<String, String> args = new HashMap<String, String>(); - if (newStateStr.equals(RepositoryVersionState.CURRENT.toString())) { - // Finalize upgrade workflow - args.put(FinalizeUpgradeAction.UPGRADE_DIRECTION_KEY, "upgrade"); - } else if (newStateStr.equals(RepositoryVersionState.INSTALLED.toString())) { - // Finalize downgrade workflow - args.put(FinalizeUpgradeAction.UPGRADE_DIRECTION_KEY, "downgrade"); - } else { - throw new IllegalArgumentException( - String.format("Invalid desired state %s. Should be either CURRENT or INSTALLED", - newStateStr)); + String forceCurrent = (String) propertyMap.get(CLUSTER_STACK_VERSION_FORCE); + boolean force = false; + if (null != forceCurrent) { + force = Boolean.parseBoolean(forceCurrent); } - // Get a host name to populate the hostrolecommand table's hostEntity. - String defaultHostName = null; - // TODO: remove direct access to cluster entity completely - ClusterEntity clusterEntity = clusterDAO.findByName(clName); - List<HostEntity> hosts = new ArrayList(clusterEntity.getHostEntities()); - if (hosts != null && !hosts.isEmpty()) { - Collections.sort(hosts); - defaultHostName = hosts.get(0).getHostName(); - } - if (defaultHostName == null) { - throw new AmbariException("Could not find at least one host to set the command for"); - } - args.put(FinalizeUpgradeAction.VERSION_KEY, desiredRepoVersion); - args.put(FinalizeUpgradeAction.CLUSTER_NAME_KEY, clName); + if (!force) { - ExecutionCommand command = new ExecutionCommand(); - command.setCommandParams(args); - command.setClusterName(clName); - finalizeUpgradeAction.setExecutionCommand(command); + Map<String, String> args = new HashMap<String, String>(); + if (newStateStr.equals(RepositoryVersionState.CURRENT.toString())) { + // Finalize upgrade workflow + args.put(FinalizeUpgradeAction.UPGRADE_DIRECTION_KEY, "upgrade"); + } else if (newStateStr.equals(RepositoryVersionState.INSTALLED.toString())) { + // Finalize downgrade workflow + args.put(FinalizeUpgradeAction.UPGRADE_DIRECTION_KEY, "downgrade"); + } else { + throw new IllegalArgumentException( + String.format("Invalid desired state %s. Should be either CURRENT or INSTALLED", + newStateStr)); + } - HostRoleCommand hostRoleCommand = hostRoleCommandFactory.create(defaultHostName, - Role.AMBARI_SERVER_ACTION, null, null); - finalizeUpgradeAction.setHostRoleCommand(hostRoleCommand); + // Get a host name to populate the hostrolecommand table's hostEntity. + String defaultHostName; + ArrayList<Host> hosts = new ArrayList<Host>(cluster.getHosts()); + if (!hosts.isEmpty()) { + defaultHostName = hosts.get(0).getHostName(); + } else { + throw new AmbariException("Could not find at least one host to set the command for"); + } - CommandReport report = finalizeUpgradeAction.execute(null); + args.put(FinalizeUpgradeAction.VERSION_KEY, desiredRepoVersion); + args.put(FinalizeUpgradeAction.CLUSTER_NAME_KEY, clName); - LOG.info("Finalize output:"); - LOG.info("STDOUT: {}", report.getStdOut()); - LOG.info("STDERR: {}", report.getStdErr()); + ExecutionCommand command = new ExecutionCommand(); + command.setCommandParams(args); + command.setClusterName(clName); + finalizeUpgradeAction.setExecutionCommand(command); - if (report.getStatus().equals(HostRoleStatus.COMPLETED.toString())) { - return getRequestStatus(null); + HostRoleCommand hostRoleCommand = hostRoleCommandFactory.create(defaultHostName, + Role.AMBARI_SERVER_ACTION, null, null); + finalizeUpgradeAction.setHostRoleCommand(hostRoleCommand); + + CommandReport report = finalizeUpgradeAction.execute(null); + + LOG.info("Finalize output:"); + LOG.info("STDOUT: {}", report.getStdOut()); + LOG.info("STDERR: {}", report.getStdErr()); + + if (report.getStatus().equals(HostRoleStatus.COMPLETED.toString())) { + return getRequestStatus(null); + } else { + String detailedOutput = "Finalization failed. More details: \n" + + "STDOUT: " + report.getStdOut() + "\n" + + "STDERR: " + report.getStdErr(); + throw new SystemException(detailedOutput); + } } else { - String detailedOutput = "Finalization failed. More details: \n" + - "STDOUT: " + report.getStdOut() + "\n" + - "STDERR: " + report.getStdErr(); - throw new SystemException(detailedOutput); + // !!! revisit for PU + ClusterVersionEntity current = cluster.getCurrentClusterVersion(); + + if (!current.getRepositoryVersion().equals(rve)) { + updateVersionStates(current.getClusterId(), current.getRepositoryVersion(), rve); + } + + + return getRequestStatus(null); } } catch (AmbariException e) { e.printStackTrace(); @@ -670,4 +692,22 @@ public class ClusterStackVersionResourceProvider extends AbstractControllerResou return healthyHosts; } + + /** + * Updates the version states. Transactional to ensure only one transaction for all updates + * @param clusterId the cluster + * @param current the repository that is current for the cluster + * @param target the target repository + */ + @Transactional + protected void updateVersionStates(Long clusterId, RepositoryVersionEntity current, + RepositoryVersionEntity target) { + + clusterVersionDAO.updateVersions(clusterId, target, current); + + hostVersionDAO.updateVersions(target, current); + + hostComponentStateDAO.updateVersions(target.getVersion()); + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/ade69a11/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 8d4c5ee..1b00a3e 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,7 +23,6 @@ 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; @@ -32,6 +31,7 @@ import org.apache.ambari.server.state.RepositoryVersionState; import org.apache.ambari.server.state.StackId; import com.google.inject.Singleton; +import com.google.inject.persist.Transactional; /** * The {@link ClusterVersionDAO} class manages the {@link ClusterVersionEntity} instances associated with a cluster. @@ -176,4 +176,38 @@ public class ClusterVersionDAO extends CrudDAO<ClusterVersionEntity, Long>{ this.create(clusterVersionEntity); return clusterVersionEntity; } + + /** + * Updates the cluster version's existing CURRENT record to the INSTALLED, and the target + * becomes CURRENT. + * @param clusterId the cluster + * @param target the repo version that will be marked as CURRENT + * @param current the cluster's current record to be marked INSTALLED + */ + @Transactional + public void updateVersions(Long clusterId, RepositoryVersionEntity target, RepositoryVersionEntity current) { + // !!! first update target to be current + StringBuilder sb = new StringBuilder("UPDATE ClusterVersionEntity cve"); + sb.append(" SET cve.state = ?1 "); + sb.append(" WHERE cve.clusterId = ?2"); + sb.append(" AND cve.repositoryVersion = ?3"); + + TypedQuery<Long> query = entityManagerProvider.get().createQuery(sb.toString(), Long.class); + daoUtils.executeUpdate(query, RepositoryVersionState.CURRENT, clusterId, target); + + // !!! then move existing current to installed + sb = new StringBuilder("UPDATE ClusterVersionEntity cve"); + sb.append(" SET cve.state = ?1 "); + sb.append(" WHERE cve.clusterId = ?2"); + sb.append(" AND cve.repositoryVersion = ?3"); + sb.append(" AND cve.state = ?4"); + + query = entityManagerProvider.get().createQuery(sb.toString(), Long.class); + daoUtils.executeUpdate(query, RepositoryVersionState.INSTALLED, clusterId, current, + RepositoryVersionState.CURRENT); + + entityManagerProvider.get().clear(); + } + + } http://git-wip-us.apache.org/repos/asf/ambari/blob/ade69a11/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentDesiredStateDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentDesiredStateDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentDesiredStateDAO.java index 2620c8c..46da9da 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentDesiredStateDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentDesiredStateDAO.java @@ -18,19 +18,21 @@ package org.apache.ambari.server.orm.dao; -import com.google.inject.Inject; -import com.google.inject.Provider; -import com.google.inject.Singleton; -import com.google.inject.persist.Transactional; +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.NoResultException; +import javax.persistence.TypedQuery; + import org.apache.ambari.server.orm.RequiresSession; import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntity; import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntityPK; import org.apache.ambari.server.orm.entities.HostEntity; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.TypedQuery; -import java.util.List; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; +import com.google.inject.persist.Transactional; @Singleton public class HostComponentDesiredStateDAO { @@ -106,4 +108,5 @@ public class HostComponentDesiredStateDAO { public void removeByPK(HostComponentDesiredStateEntityPK primaryKey) { remove(findByPK(primaryKey)); } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/ade69a11/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentStateDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentStateDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentStateDAO.java index d5707be..4441b56 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentStateDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostComponentStateDAO.java @@ -18,6 +18,7 @@ package org.apache.ambari.server.orm.dao; +import java.util.Arrays; import java.util.List; import javax.persistence.EntityManager; @@ -27,6 +28,7 @@ import javax.persistence.TypedQuery; import org.apache.ambari.server.orm.RequiresSession; import org.apache.ambari.server.orm.entities.HostComponentStateEntity; import org.apache.ambari.server.orm.entities.HostEntity; +import org.apache.ambari.server.state.UpgradeState; import com.google.inject.Inject; import com.google.inject.Provider; @@ -182,4 +184,30 @@ public class HostComponentStateDAO { hostEntity.removeHostComponentStateEntity(hostComponentStateEntity); hostDAO.merge(hostEntity); } + + /** + * Marks hosts components to the specified version that are NOT already set or "UNKNOWN". + * Also marks all host components as not being upgraded. + * + * @param version the version + */ + @Transactional + public void updateVersions(String version) { + // !!! first the version + StringBuilder sb = new StringBuilder("UPDATE HostComponentStateEntity hostComponent"); + sb.append(" SET hostComponent.version = ?1 "); + sb.append(" WHERE hostComponent.version NOT IN ?2"); + + TypedQuery<Long> query = entityManagerProvider.get().createQuery(sb.toString(), Long.class); + daoUtils.executeUpdate(query, version, Arrays.asList(version, "UNKNOWN")); + + // !!! now the upgrade state + sb = new StringBuilder("UPDATE HostComponentStateEntity hostComponent"); + sb.append(" SET hostComponent.upgradeState = ?1"); + + query = entityManagerProvider.get().createQuery(sb.toString(), Long.class); + daoUtils.executeUpdate(query, UpgradeState.NONE); + + entityManagerProvider.get().clear(); + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/ade69a11/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 ad617af..ae63263 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 @@ -28,6 +28,7 @@ import javax.persistence.TypedQuery; import org.apache.ambari.server.orm.RequiresSession; import org.apache.ambari.server.orm.entities.HostVersionEntity; +import org.apache.ambari.server.orm.entities.RepositoryVersionEntity; import org.apache.ambari.server.state.RepositoryVersionState; import org.apache.ambari.server.state.StackId; @@ -192,4 +193,35 @@ public class HostVersionDAO extends CrudDAO<HostVersionEntity, Long> { this.remove(hostVersion); } } + + /** + * Updates the host versions existing CURRENT record to the INSTALLED, and the target + * becomes CURRENT. + * @param target the repo version that all hosts to mark as CURRENT + * @param current the repo version that all hosts marked as INSTALLED + */ + @Transactional + public void updateVersions(RepositoryVersionEntity target, RepositoryVersionEntity current) { + // !!! first update target to be current + StringBuilder sb = new StringBuilder("UPDATE HostVersionEntity hve"); + sb.append(" SET hve.state = ?1 "); + sb.append(" WHERE hve.repositoryVersion = ?2"); + + TypedQuery<Long> query = entityManagerProvider.get().createQuery(sb.toString(), Long.class); + daoUtils.executeUpdate(query, RepositoryVersionState.CURRENT, target); + + // !!! then move existing current to installed + sb = new StringBuilder("UPDATE HostVersionEntity hve"); + sb.append(" SET hve.state = ?1 "); + sb.append(" WHERE hve.repositoryVersion = ?2"); + sb.append(" AND hve.state = ?3"); + + query = entityManagerProvider.get().createQuery(sb.toString(), Long.class); + daoUtils.executeUpdate(query, RepositoryVersionState.INSTALLED, current, + RepositoryVersionState.CURRENT); + + + entityManagerProvider.get().clear(); + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/ade69a11/ambari-server/src/main/python/ambari-server.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/python/ambari-server.py b/ambari-server/src/main/python/ambari-server.py index 2963322..9f8f925 100755 --- a/ambari-server/src/main/python/ambari-server.py +++ b/ambari-server/src/main/python/ambari-server.py @@ -372,7 +372,7 @@ def init_parser_options(parser): dest="jdbc_db") parser.add_option('--cluster-name', default=None, help="Cluster name", dest="cluster_name") parser.add_option('--version-display-name', default=None, help="Display name of desired repo version", dest="desired_repo_version") - + parser.add_option('--force-version', action="store_true", default=False, help="Force version to current", dest="force_repo_version") @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY) def are_cmd_line_db_args_blank(options): http://git-wip-us.apache.org/repos/asf/ambari/blob/ade69a11/ambari-server/src/main/python/ambari_server/serverUpgrade.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/python/ambari_server/serverUpgrade.py b/ambari-server/src/main/python/ambari_server/serverUpgrade.py index 7048812..f05082f 100644 --- a/ambari-server/src/main/python/ambari_server/serverUpgrade.py +++ b/ambari-server/src/main/python/ambari_server/serverUpgrade.py @@ -411,7 +411,8 @@ def set_current(options): data = { "ClusterStackVersions": { "repository_version": finalize_options.desired_repo_version, - "state": "CURRENT" + "state": "CURRENT", + "force": "true" if finalize_options.force_repo_version else "false" } } @@ -497,5 +498,10 @@ class SetCurrentVersionOptions: except AttributeError: self.desired_repo_version = None + try: + self.force_repo_version = options.force_repo_version + except AttributeError: + self.force_repo_version = False + def no_finalize_options_set(self): return self.cluster_name is None or self.desired_repo_version is None http://git-wip-us.apache.org/repos/asf/ambari/blob/ade69a11/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java index 7b37483..b41416e 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ClusterStackVersionResourceProviderTest.java @@ -60,7 +60,10 @@ import org.apache.ambari.server.controller.utilities.PropertyHelper; import org.apache.ambari.server.orm.GuiceJpaInitializer; import org.apache.ambari.server.orm.InMemoryDefaultTestModule; import org.apache.ambari.server.orm.dao.ClusterDAO; +import org.apache.ambari.server.orm.dao.ClusterVersionDAO; +import org.apache.ambari.server.orm.dao.HostComponentStateDAO; import org.apache.ambari.server.orm.dao.HostDAO; +import org.apache.ambari.server.orm.dao.HostVersionDAO; import org.apache.ambari.server.orm.dao.RepositoryVersionDAO; import org.apache.ambari.server.orm.dao.ResourceTypeDAO; import org.apache.ambari.server.orm.dao.StackDAO; @@ -111,6 +114,9 @@ public class ClusterStackVersionResourceProviderTest { private Configuration configuration; private StageFactory stageFactory; + private HostVersionDAO hostVersionDAO; + private HostComponentStateDAO hostComponentStateDAO; + private String operatingSystemsJson = "[\n" + " {\n" + " \"repositories\":[\n" + @@ -134,6 +140,9 @@ public class ClusterStackVersionResourceProviderTest { public void setup() throws Exception { // Create instances of mocks repositoryVersionDAOMock = createNiceMock(RepositoryVersionDAO.class); + hostVersionDAO = createNiceMock(HostVersionDAO.class); + hostComponentStateDAO = createNiceMock(HostComponentStateDAO.class); + configHelper = createNiceMock(ConfigHelper.class); InMemoryDefaultTestModule inMemoryModule = new InMemoryDefaultTestModule(); Properties properties = inMemoryModule.getProperties(); @@ -150,6 +159,7 @@ public class ClusterStackVersionResourceProviderTest { stackDAO = injector.getInstance(StackDAO.class); clusterDAO = injector.getInstance(ClusterDAO.class); hostDAO = injector.getInstance(HostDAO.class); + } @After @@ -449,6 +459,153 @@ public class ClusterStackVersionResourceProviderTest { Assert.assertEquals(clusterEntity.getDesiredStack(), newDesiredStack); } + /** + * Tests manual finalization scenario + * @throws Exception + */ + @Test + public void testUpdateResourcesWithForce() throws Exception { + + + Resource.Type type = Resource.Type.ClusterStackVersion; + String clusterName = "Cluster100"; + + AmbariManagementController managementController = createMock(AmbariManagementController.class); + + StackId stackId = new StackId("HDP", "2.0.1"); + StackEntity stackEntity = stackDAO.find(stackId.getStackName(), stackId.getStackVersion()); + Assert.assertNotNull(stackEntity); + + ResourceTypeEntity resourceTypeEntity = resourceTypeDAO.findById(ResourceTypeEntity.CLUSTER_RESOURCE_TYPE); + if (resourceTypeEntity == null) { + resourceTypeEntity = new ResourceTypeEntity(); + resourceTypeEntity.setId(ResourceTypeEntity.CLUSTER_RESOURCE_TYPE); + resourceTypeEntity.setName(ResourceTypeEntity.CLUSTER_RESOURCE_TYPE_NAME); + resourceTypeEntity = resourceTypeDAO.merge(resourceTypeEntity); + } + ResourceEntity resourceEntity = new ResourceEntity(); + resourceEntity.setResourceType(resourceTypeEntity); + + final Host host1 = createNiceMock("host1", Host.class); + final Host host2 = createNiceMock("host2", Host.class); + + expect(host1.getHostName()).andReturn("host1").anyTimes(); + expect(host2.getHostName()).andReturn("host2").anyTimes(); + replay(host1, host2); + + ServiceComponentHost sch = createMock(ServiceComponentHost.class); + List<ServiceComponentHost> schs = Collections.singletonList(sch); + + Cluster cluster = createNiceMock(Cluster.class); + cluster.setClusterName(clusterName); + + ArrayList<Host> hosts = new ArrayList<Host>() {{ + add(host1); + add(host2); + }}; + + Clusters clusters = createNiceMock(Clusters.class); + expect(clusters.getCluster(anyObject(String.class))).andReturn(cluster); + + RepositoryVersionEntity repoVersion = new RepositoryVersionEntity(); + repoVersion.setOperatingSystems(operatingSystemsJson); + StackEntity newDesiredStack = stackDAO.find("HDP", "2.0.1"); + repoVersion.setStack(newDesiredStack); + + final ServiceOsSpecific.Package hivePackage = new ServiceOsSpecific.Package(); + hivePackage.setName("hive"); + final ServiceOsSpecific.Package mysqlPackage = new ServiceOsSpecific.Package(); + mysqlPackage.setName("mysql"); + mysqlPackage.setSkipUpgrade(Boolean.TRUE); + List<ServiceOsSpecific.Package> packages = new ArrayList<ServiceOsSpecific.Package>() {{ + add(hivePackage); + add(mysqlPackage); + }}; + + ActionManager actionManager = createNiceMock(ActionManager.class); + + RequestStatusResponse response = createNiceMock(RequestStatusResponse.class); + ResourceProviderFactory resourceProviderFactory = createNiceMock(ResourceProviderFactory.class); + ResourceProvider csvResourceProvider = createNiceMock(ClusterStackVersionResourceProvider.class); + + AbstractControllerResourceProvider.init(resourceProviderFactory); + + Map<String, Map<String, String>> hostConfigTags = new HashMap<String, Map<String, String>>(); + expect(configHelper.getEffectiveDesiredTags(anyObject(ClusterImpl.class), anyObject(String.class))).andReturn(hostConfigTags); + + expect(managementController.getClusters()).andReturn(clusters).anyTimes(); + expect(managementController.getAmbariMetaInfo()).andReturn(ambariMetaInfo).anyTimes(); + expect(managementController.getAuthName()).andReturn("admin").anyTimes(); + expect(managementController.getActionManager()).andReturn(actionManager).anyTimes(); + expect(managementController.getJdkResourceUrl()).andReturn("/JdkResourceUrl").anyTimes(); + expect(managementController.getPackagesForServiceHost(anyObject(ServiceInfo.class), + (Map<String, String>) anyObject(List.class), anyObject(String.class))).andReturn(packages).anyTimes(); + + expect(resourceProviderFactory.getHostResourceProvider(anyObject(Set.class), anyObject(Map.class), + eq(managementController))).andReturn(csvResourceProvider).anyTimes(); + + expect(cluster.getCurrentStackVersion()).andReturn(stackId); + expect(cluster.getServiceComponentHosts(anyObject(String.class))).andReturn(schs).anyTimes(); + + RepositoryVersionEntity currentRepo = new RepositoryVersionEntity(); + currentRepo.setVersion("2.2.2.0-2122"); + ClusterVersionEntity current = new ClusterVersionEntity(); + current.setRepositoryVersion(currentRepo); + + Capture<StackId> capturedStackId = new Capture<StackId>(); + cluster.setDesiredStackVersion(capture(capturedStackId)); + expectLastCall().once(); + expect(cluster.getHosts()).andReturn(hosts).anyTimes(); + expect(cluster.getCurrentClusterVersion()).andReturn(current).anyTimes(); + + expect(sch.getServiceName()).andReturn("HIVE").anyTimes(); + + expect(repositoryVersionDAOMock.findByDisplayName(anyObject(String.class))).andReturn(repoVersion); + + clusterVersionDAO.updateVersions((Long) anyObject(), + (RepositoryVersionEntity) anyObject(), (RepositoryVersionEntity) anyObject()); + expectLastCall().once(); + + hostVersionDAO.updateVersions((RepositoryVersionEntity) anyObject(), (RepositoryVersionEntity) anyObject()); + expectLastCall().once(); + + hostComponentStateDAO.updateVersions((String) anyObject()); + expectLastCall().once(); + + // replay + replay(managementController, response, clusters, resourceProviderFactory, csvResourceProvider, + cluster, repositoryVersionDAOMock, configHelper, sch, actionManager, clusterVersionDAO, + hostVersionDAO, hostComponentStateDAO); + + ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider( + type, + PropertyHelper.getPropertyIds(type), + PropertyHelper.getKeyPropertyIds(type), + managementController); + + injector.injectMembers(provider); + + + // add the property map to a set for the request. add more maps for multiple creates + Map<String, Object> properties = new LinkedHashMap<String, Object>(); + + // add properties to the request map + properties.put(ClusterStackVersionResourceProvider.CLUSTER_STACK_VERSION_CLUSTER_NAME_PROPERTY_ID, clusterName); + properties.put(ClusterStackVersionResourceProvider.CLUSTER_STACK_VERSION_STATE_PROPERTY_ID, "CURRENT"); + properties.put(ClusterStackVersionResourceProvider.CLUSTER_STACK_VERSION_REPOSITORY_VERSION_PROPERTY_ID, "HDP-2.2.2.0-2561"); + properties.put(ClusterStackVersionResourceProvider.CLUSTER_STACK_VERSION_FORCE, "true"); + + // create the request + Request request = PropertyHelper.getUpdateRequest(properties, null); + + provider.updateResources(request, null); + + // verify + verify(managementController, response, clusterVersionDAO, hostVersionDAO, hostComponentStateDAO); + Assert.assertEquals(capturedStackId.getValue(), + new StackId(newDesiredStack.getStackName(), newDesiredStack.getStackVersion())); + } + public class MockModule extends AbstractModule { @Override @@ -457,6 +614,9 @@ public class ClusterStackVersionResourceProviderTest { bind(ConfigHelper.class).toInstance(configHelper); bind(Configuration.class).toInstance(configuration); bind(StageFactory.class).toInstance(stageFactory); + bind(ClusterVersionDAO.class).toInstance(clusterVersionDAO); + bind(HostVersionDAO.class).toInstance(hostVersionDAO); + bind(HostComponentStateDAO.class).toInstance(hostComponentStateDAO); } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/ade69a11/ambari-server/src/test/python/TestServerUpgrade.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/python/TestServerUpgrade.py b/ambari-server/src/test/python/TestServerUpgrade.py index 7ef74b2..50e023f 100644 --- a/ambari-server/src/test/python/TestServerUpgrade.py +++ b/ambari-server/src/test/python/TestServerUpgrade.py @@ -39,6 +39,7 @@ class TestServerUpgrade(TestCase): options = MagicMock() options.cluster_name = 'cc' options.desired_repo_version = 'HDP-2.2.2.0-2561' + options.force_repo_version = None # Case when server is not running is_server_runing_mock.return_value = False, None @@ -75,11 +76,63 @@ class TestServerUpgrade(TestCase): self.assertTrue(urlopen_mock.called) request = urlopen_mock.call_args_list[0][0][0] self.assertEquals(request._Request__original, 'http://127.0.0.1:8080/api/v1/clusters/cc/stack_versions') - self.assertEquals(request.data, '{"ClusterStackVersions": {"state": "CURRENT", "repository_version": "HDP-2.2.2.0-2561"}}') + self.assertEquals(request.data, '{"ClusterStackVersions": {"state": "CURRENT", "repository_version": "HDP-2.2.2.0-2561", "force": "false"}}') self.assertEquals(request.origin_req_host, '127.0.0.1') self.assertEquals(request.headers, {'X-requested-by': 'ambari', 'Authorization': 'Basic ZHVtbXlfc3RyaW5nOmR1bW15X3N0cmluZw=='}) + @patch("ambari_server.serverUpgrade.is_server_runing") + @patch('ambari_server.serverUpgrade.SetCurrentVersionOptions.no_finalize_options_set') + @patch('ambari_server.serverUpgrade.get_validated_string_input') + @patch('ambari_server.serverUpgrade.get_ambari_properties') + @patch('ambari_server.serverUtils.get_ambari_server_api_base') + @patch('ambari_commons.logging_utils.get_verbose') + @patch('urllib2.urlopen') + def test_set_current_with_force(self, urlopen_mock, get_verbose_mock, get_ambari_server_api_base_mock, + get_ambari_properties_mock, get_validated_string_input_mock, + no_finalize_options_set_mock, is_server_runing_mock): + options = MagicMock() + options.cluster_name = 'cc' + options.desired_repo_version = 'HDP-2.2.2.0-2561' + options.force_repo_version = True + # Case when server is not running + is_server_runing_mock.return_value = False, None + try: + set_current(options) + self.fail("Server is not running - should error out") + except FatalException: + pass # expected + + + is_server_runing_mock.return_value = True, 11111 + + # Test insufficient options case + no_finalize_options_set_mock.return_value = True + try: + set_current(options) + self.fail("Should error out") + except FatalException: + pass # expected + + no_finalize_options_set_mock.return_value = False + + # Test normal flow + get_validated_string_input_mock.return_value = 'dummy_string' + + p = get_ambari_properties_mock.return_value + p.get_property.side_effect = ["8080", "false"] + + get_ambari_server_api_base_mock.return_value = 'http://127.0.0.1:8080/api/v1/' + get_verbose_mock.retun_value = False + + set_current(options) + + self.assertTrue(urlopen_mock.called) + request = urlopen_mock.call_args_list[0][0][0] + self.assertEquals(request._Request__original, 'http://127.0.0.1:8080/api/v1/clusters/cc/stack_versions') + self.assertEquals(request.data, '{"ClusterStackVersions": {"state": "CURRENT", "repository_version": "HDP-2.2.2.0-2561", "force": "true"}}') + self.assertEquals(request.origin_req_host, '127.0.0.1') + self.assertEquals(request.headers, {'X-requested-by': 'ambari', 'Authorization': 'Basic ZHVtbXlfc3RyaW5nOmR1bW15X3N0cmluZw=='}) def testCurrentVersionOptions(self): # Negative test cases
