Repository: ambari Updated Branches: refs/heads/branch-2.1 aa283e6a9 -> 0aeb37719
AMBARI-12150. RU - Pre Reqs incorrectly reports that services are down (alejandro) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/0aeb3771 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/0aeb3771 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/0aeb3771 Branch: refs/heads/branch-2.1 Commit: 0aeb377195ac372d2baa38f0622747741b79965d Parents: aa283e6 Author: Alejandro Fernandez <[email protected]> Authored: Fri Jun 26 20:27:32 2015 -0700 Committer: Alejandro Fernandez <[email protected]> Committed: Fri Jun 26 20:27:32 2015 -0700 ---------------------------------------------------------------------- ambari-server/pom.xml | 15 +- .../ambari/server/checks/CheckDescription.java | 2 +- .../ambari/server/checks/ServicesUpCheck.java | 58 +++++++- .../orm/dao/HostComponentDesiredStateDAO.java | 24 ++- .../server/orm/dao/HostComponentStateDAO.java | 48 ++++++ .../HostComponentDesiredStateEntity.java | 17 +++ .../orm/entities/HostComponentStateEntity.java | 10 ++ .../server/orm/models/HostComponentSummary.java | 104 +++++++++++++ .../ambari/server/state/ServiceComponent.java | 2 + .../server/state/ServiceComponentImpl.java | 9 ++ .../stacks/HDP/2.3/upgrades/upgrade-2.3.xml | 2 +- .../server/checks/ServicesUpCheckTest.java | 147 ++++++++++++++++++- 12 files changed, 416 insertions(+), 22 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/0aeb3771/ambari-server/pom.xml ---------------------------------------------------------------------- diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml index 7a8ff09..4790ff4 100644 --- a/ambari-server/pom.xml +++ b/ambari-server/pom.xml @@ -40,6 +40,7 @@ <ambari-web-dir>${basedir}/../ambari-web/public</ambari-web-dir> <ambari-admin-dir>${basedir}/../ambari-admin</ambari-admin-dir> <contrib-views-dir>${basedir}/../contrib/views</contrib-views-dir> + <powermock.version>1.5</powermock.version> </properties> <build> <plugins> @@ -1727,25 +1728,31 @@ <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-core</artifactId> - <version>1.5</version> + <version>${powermock.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-reflect</artifactId> - <version>1.5</version> + <version>${powermock.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-easymock</artifactId> - <version>1.5</version> + <version>${powermock.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> - <version>1.5</version> + <version>${powermock.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito</artifactId> + <version>1.4.9</version> <scope>test</scope> </dependency> <dependency> http://git-wip-us.apache.org/repos/asf/ambari/blob/0aeb3771/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java index 23a575a..5e029f4 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/CheckDescription.java @@ -130,7 +130,7 @@ public enum CheckDescription { "All services must be started", new HashMap<String, String>() {{ put(AbstractCheckDescriptor.DEFAULT, - "The following Services must be started: {{fails}}"); + "The following Services must be started: {{fails}}. Try to do a Stop & Start in case they were started outside of Ambari."); }}), SERVICES_YARN_WP(PrereqCheckType.SERVICE, http://git-wip-us.apache.org/repos/asf/ambari/blob/0aeb3771/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesUpCheck.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesUpCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesUpCheck.java index 243b26d..00c798b 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesUpCheck.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/ServicesUpCheck.java @@ -17,17 +17,27 @@ */ package org.apache.ambari.server.checks; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; +import com.google.inject.Inject; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.controller.PrereqCheckRequest; +import org.apache.ambari.server.orm.dao.HostDAO; +import org.apache.ambari.server.orm.models.HostComponentSummary; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Service; +import org.apache.ambari.server.state.ServiceComponent; import org.apache.ambari.server.state.State; import org.apache.ambari.server.state.stack.PrereqCheckStatus; import org.apache.ambari.server.state.stack.PrerequisiteCheck; import com.google.inject.Singleton; +import org.apache.commons.lang.StringUtils; /** * Checks that services are up. @@ -45,21 +55,57 @@ public class ServicesUpCheck extends AbstractCheckDescriptor { @Override public void perform(PrerequisiteCheck prerequisiteCheck, PrereqCheckRequest request) throws AmbariException { - final String clusterName = request.getClusterName(); final Cluster cluster = clustersProvider.get().getCluster(clusterName); - for (Map.Entry<String, Service> serviceEntry : cluster.getServices().entrySet()) { + List<String> errorMessages = new ArrayList<String>(); + Set<String> failedServiceNames = new HashSet<String>(); + for (Map.Entry<String, Service> serviceEntry : cluster.getServices().entrySet()) { final Service service = serviceEntry.getValue(); - if (!service.isClientOnlyService() && service.getDesiredState() != State.STARTED) { - prerequisiteCheck.getFailedOn().add(service.getName()); + // Ignore services like Tez that are clientOnly. + if (!service.isClientOnlyService()) { + Map<String, ServiceComponent> serviceComponents = service.getServiceComponents(); + + for (Map.Entry<String, ServiceComponent> component : serviceComponents.entrySet()) { + + boolean ignoreComponent = false; + + ServiceComponent serviceComponent = component.getValue(); + // In Services like HDFS, ignore components like HDFS Client + if (serviceComponent.isClientComponent()) { + ignoreComponent = true; + } + + if (!serviceComponent.isVersionAdvertised()) { + ignoreComponent = true; + } + + // TODO, add more logic that checks the Upgrade Pack. + // These components are not in the upgrade pack and do not advertise a version: + // ZKFC, Ambari Metrics, Kerberos, Atlas (right now). + // Generally, if it advertises a version => in the upgrade pack. + // So it can be in the Upgrade Pack but not advertise a version. + if (!ignoreComponent) { + List<HostComponentSummary> hostComponentSummaries = HostComponentSummary.getHostComponentSummaries(service.getName(), serviceComponent.getName()); + + for(HostComponentSummary s : hostComponentSummaries) { + if ((s.getDesiredState() == State.INSTALLED || s.getDesiredState() == State.STARTED) && State.STARTED != s.getCurrentState()) { + failedServiceNames.add(service.getName()); + String message = MessageFormat.format("{0} - {1} (in {2} on host {3})", service.getName(), serviceComponent.getName(), s.getCurrentState(), s.getHostName()); + errorMessages.add(message); + continue; + } + } + } + } } } - if (!prerequisiteCheck.getFailedOn().isEmpty()) { + if (!errorMessages.isEmpty()) { + prerequisiteCheck.setFailedOn(new ArrayList<String>(failedServiceNames)); prerequisiteCheck.setStatus(PrereqCheckStatus.FAIL); - prerequisiteCheck.setFailReason(getFailReason(prerequisiteCheck, request)); + prerequisiteCheck.setFailReason("The following Service Components should be in a started state. Please invoke a service Stop and full Start and try again. " + StringUtils.join(errorMessages, ", ")); } } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/0aeb3771/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 2d699b7..2620c8c 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 @@ -40,6 +40,9 @@ public class HostComponentDesiredStateDAO { @Inject HostDAO hostDAO; + @Inject + DaoUtils daoUtils; + @RequiresSession public HostComponentDesiredStateEntity findByPK(HostComponentDesiredStateEntityPK primaryKey) { return entityManagerProvider.get().find(HostComponentDesiredStateEntity.class, primaryKey); @@ -47,8 +50,7 @@ public class HostComponentDesiredStateDAO { @RequiresSession public List<HostComponentDesiredStateEntity> findAll() { - TypedQuery<HostComponentDesiredStateEntity> query = entityManagerProvider.get() - .createQuery("SELECT hcd from HostComponentDesiredStateEntity hcd", HostComponentDesiredStateEntity.class); + final TypedQuery<HostComponentDesiredStateEntity> query = entityManagerProvider.get().createNamedQuery("HostComponentDesiredStateEntity.findAll", HostComponentDesiredStateEntity.class); try { return query.getResultList(); } catch (NoResultException ignored) { @@ -56,6 +58,24 @@ public class HostComponentDesiredStateDAO { return null; } + /** + * Retrieve the single Host Component Desired State for the given unique service, component, and host. + * + * @param serviceName Service Name + * @param componentName Component Name + * @param hostName Host Name + * @return Return all of the Host Component States that match the criteria. + */ + @RequiresSession + public HostComponentDesiredStateEntity findByServiceComponentAndHost(String serviceName, String componentName, String hostName) { + final TypedQuery<HostComponentDesiredStateEntity> query = entityManagerProvider.get().createNamedQuery("HostComponentDesiredStateEntity.findByServiceComponentAndHost", HostComponentDesiredStateEntity.class); + query.setParameter("serviceName", serviceName); + query.setParameter("componentName", componentName); + query.setParameter("hostName", hostName); + + return daoUtils.selectSingle(query); + } + @Transactional public void refresh(HostComponentDesiredStateEntity hostComponentDesiredStateEntity) { entityManagerProvider.get().refresh(hostComponentDesiredStateEntity); http://git-wip-us.apache.org/repos/asf/ambari/blob/0aeb3771/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 e7b5c10..00ffd5a 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 @@ -71,6 +71,54 @@ public class HostComponentStateDAO { return daoUtils.selectList(query); } + /** + * Retrieve all of the Host Component States for the given service. + * + * @param serviceName Service Name + * @return Return all of the Host Component States that match the criteria. + */ + @RequiresSession + public List<HostComponentStateEntity> findByService(String serviceName) { + final TypedQuery<HostComponentStateEntity> query = entityManagerProvider.get().createNamedQuery("HostComponentStateEntity.findByService", HostComponentStateEntity.class); + query.setParameter("serviceName", serviceName); + + return daoUtils.selectList(query); + } + + /** + * Retrieve all of the Host Component States for the given service and component. + * + * @param serviceName Service Name + * @param componentName Component Name + * @return Return all of the Host Component States that match the criteria. + */ + @RequiresSession + public List<HostComponentStateEntity> findByServiceAndComponent(String serviceName, String componentName) { + final TypedQuery<HostComponentStateEntity> query = entityManagerProvider.get().createNamedQuery("HostComponentStateEntity.findByServiceAndComponent", HostComponentStateEntity.class); + query.setParameter("serviceName", serviceName); + query.setParameter("componentName", componentName); + + return daoUtils.selectList(query); + } + + /** + * Retrieve the single Host Component State for the given unique service, component, and host. + * + * @param serviceName Service Name + * @param componentName Component Name + * @param hostName Host Name + * @return Return all of the Host Component States that match the criteria. + */ + @RequiresSession + public HostComponentStateEntity findByServiceComponentAndHost(String serviceName, String componentName, String hostName) { + final TypedQuery<HostComponentStateEntity> query = entityManagerProvider.get().createNamedQuery("HostComponentStateEntity.findByServiceComponentAndHost", HostComponentStateEntity.class); + query.setParameter("serviceName", serviceName); + query.setParameter("componentName", componentName); + query.setParameter("hostName", hostName); + + return daoUtils.selectSingle(query); + } + @Transactional public void refresh(HostComponentStateEntity hostComponentStateEntity) { entityManagerProvider.get().refresh(hostComponentStateEntity); http://git-wip-us.apache.org/repos/asf/ambari/blob/0aeb3771/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostComponentDesiredStateEntity.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostComponentDesiredStateEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostComponentDesiredStateEntity.java index 570c84b..101aea1 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostComponentDesiredStateEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostComponentDesiredStateEntity.java @@ -29,6 +29,8 @@ import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinColumns; import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; import javax.persistence.OneToOne; import org.apache.ambari.server.state.HostComponentAdminState; @@ -39,6 +41,21 @@ import org.apache.ambari.server.state.State; @javax.persistence.IdClass(HostComponentDesiredStateEntityPK.class) @javax.persistence.Table(name = "hostcomponentdesiredstate") @Entity +@NamedQueries({ + @NamedQuery(name = "HostComponentDesiredStateEntity.findAll", query = "SELECT hcds from HostComponentDesiredStateEntity hcds"), + + @NamedQuery(name = "HostComponentDesiredStateEntity.findByHost", query = + "SELECT hcds from HostComponentDesiredStateEntity hcds WHERE hcds.hostEntity.hostName=:hostName"), + + @NamedQuery(name = "HostComponentDesiredStateEntity.findByService", query = + "SELECT hcds from HostComponentDesiredStateEntity hcds WHERE hcds.serviceName=:serviceName"), + + @NamedQuery(name = "HostComponentDesiredStateEntity.findByServiceAndComponent", query = + "SELECT hcds from HostComponentDesiredStateEntity hcds WHERE hcds.serviceName=:serviceName AND hcds.componentName=:componentName"), + + @NamedQuery(name = "HostComponentDesiredStateEntity.findByServiceComponentAndHost", query = + "SELECT hcds from HostComponentDesiredStateEntity hcds WHERE hcds.serviceName=:serviceName AND hcds.componentName=:componentName AND hcds.hostEntity.hostName=:hostName"), +}) public class HostComponentDesiredStateEntity { @Id http://git-wip-us.apache.org/repos/asf/ambari/blob/0aeb3771/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostComponentStateEntity.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostComponentStateEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostComponentStateEntity.java index dabe98b..45e036b 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostComponentStateEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/HostComponentStateEntity.java @@ -42,8 +42,18 @@ import org.apache.ambari.server.state.UpgradeState; @Entity @NamedQueries({ @NamedQuery(name = "HostComponentStateEntity.findAll", query = "SELECT hcs from HostComponentStateEntity hcs"), + @NamedQuery(name = "HostComponentStateEntity.findByHost", query = "SELECT hcs from HostComponentStateEntity hcs WHERE hcs.hostEntity.hostName=:hostName"), + + @NamedQuery(name = "HostComponentStateEntity.findByService", query = + "SELECT hcs from HostComponentStateEntity hcs WHERE hcs.serviceName=:serviceName"), + + @NamedQuery(name = "HostComponentStateEntity.findByServiceAndComponent", query = + "SELECT hcs from HostComponentStateEntity hcs WHERE hcs.serviceName=:serviceName AND hcs.componentName=:componentName"), + + @NamedQuery(name = "HostComponentStateEntity.findByServiceComponentAndHost", query = + "SELECT hcs from HostComponentStateEntity hcs WHERE hcs.serviceName=:serviceName AND hcs.componentName=:componentName AND hcs.hostEntity.hostName=:hostName"), }) public class HostComponentStateEntity { http://git-wip-us.apache.org/repos/asf/ambari/blob/0aeb3771/ambari-server/src/main/java/org/apache/ambari/server/orm/models/HostComponentSummary.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/models/HostComponentSummary.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/models/HostComponentSummary.java new file mode 100644 index 0000000..c79ec8a --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/models/HostComponentSummary.java @@ -0,0 +1,104 @@ +/** + * 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.orm.models; + +import com.google.inject.Inject; +import org.apache.ambari.server.StaticallyInject; +import org.apache.ambari.server.orm.dao.HostComponentDesiredStateDAO; +import org.apache.ambari.server.orm.dao.HostComponentStateDAO; +import org.apache.ambari.server.orm.dao.HostDAO; +import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntity; +import org.apache.ambari.server.orm.entities.HostComponentStateEntity; +import org.apache.ambari.server.orm.entities.HostEntity; +import org.apache.ambari.server.state.State; + +import java.util.ArrayList; +import java.util.List; + +@StaticallyInject +public class HostComponentSummary { + private String serviceName; + private String componentName; + private Long hostId; + private String hostName; + private State desiredState; + private State currentState; + + @Inject + private static HostDAO hostDao; + + @Inject + private static HostComponentStateDAO hostComponentStateDao; + + @Inject + private static HostComponentDesiredStateDAO hostComponentDesiredStateDao; + + public HostComponentSummary(String serviceName, String componentName, Long hostId, State desiredState, State currentState) { + this.serviceName = serviceName; + this.componentName = componentName; + this.hostId = hostId; + + HostEntity host = hostDao.findById(hostId); + if (host != null) { + this.hostName = host.getHostName(); + } + + this.desiredState = desiredState; + this.currentState = currentState; + } + + public String getHostName() { + return (this.hostName == null || this.hostName.isEmpty()) ? "" : this.hostName; + } + + public State getDesiredState() { + return desiredState; + } + + public State getCurrentState() { + return currentState; + } + + public static List<HostComponentSummary> getHostComponentSummaries(String serviceName, String componentName) { + List<HostComponentSummary> hostComponentSummaries = new ArrayList<HostComponentSummary>(); + List<HostComponentStateEntity> hostComponentStates = hostComponentStateDao.findByServiceAndComponent(serviceName, componentName); + + if (hostComponentStates != null) { + for (HostComponentStateEntity hcse : hostComponentStates) { + // Find the corresponding record for HostComponentDesiredStateEntity + HostComponentDesiredStateEntity hcdse = hostComponentDesiredStateDao.findByServiceComponentAndHost(hcse.getServiceName(), hcse.getComponentName(), hcse.getHostName()); + if (hcdse != null) { + HostComponentSummary s = new HostComponentSummary(hcse.getServiceName(), hcse.getComponentName(), hcse.getHostId(), hcdse.getDesiredState(), hcse.getCurrentState()); + + hostComponentSummaries.add(s); + } + } + } + return hostComponentSummaries; + } + + @Override + public int hashCode() { + int result = 1; + result = 31 + (serviceName != null ? serviceName.hashCode() : 0); + result = result + (componentName != null ? componentName.hashCode() : 0); + result = result + (hostId != null ? hostId.hashCode() : 0); + return result; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/0aeb3771/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponent.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponent.java index 65c37f4..60a16eb 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponent.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponent.java @@ -70,6 +70,8 @@ public interface ServiceComponent { public boolean isMasterComponent(); + public boolean isVersionAdvertised(); + public boolean canBeRemoved(); public void deleteAllServiceComponentHosts() throws AmbariException; http://git-wip-us.apache.org/repos/asf/ambari/blob/0aeb3771/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java index 560cd04..aa147de 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ServiceComponentImpl.java @@ -61,6 +61,7 @@ public class ServiceComponentImpl implements ServiceComponent { private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private final boolean isClientComponent; private final boolean isMasterComponent; + private final boolean isVersionAdvertised; volatile boolean persisted = false; @Inject private ServiceComponentDesiredStateDAO serviceComponentDesiredStateDAO; @@ -101,6 +102,7 @@ public class ServiceComponentImpl implements ServiceComponent { stackId.getStackVersion(), service.getName(), componentName); isClientComponent = compInfo.isClient(); isMasterComponent = compInfo.isMaster(); + isVersionAdvertised = compInfo.isVersionAdvertised(); } catch (ObjectNotFoundException e) { throw new RuntimeException("Trying to create a ServiceComponent" + " not recognized in stack info" @@ -149,6 +151,7 @@ public class ServiceComponentImpl implements ServiceComponent { getName()); isClientComponent = compInfo.isClient(); isMasterComponent = compInfo.isMaster(); + isVersionAdvertised = compInfo.isVersionAdvertised(); } catch (ObjectNotFoundException e) { throw new AmbariException("Trying to create a ServiceComponent" + " not recognized in stack info" @@ -532,6 +535,12 @@ public class ServiceComponentImpl implements ServiceComponent { return isMasterComponent; } + + @Override + public boolean isVersionAdvertised() { + return isVersionAdvertised; + } + @Override public boolean canBeRemoved() { clusterGlobalLock.readLock().lock(); http://git-wip-us.apache.org/repos/asf/ambari/blob/0aeb3771/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/upgrade-2.3.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/upgrade-2.3.xml b/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/upgrade-2.3.xml index 1884f2e..3762422 100644 --- a/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/upgrade-2.3.xml +++ b/ambari-server/src/main/resources/stacks/HDP/2.3/upgrades/upgrade-2.3.xml @@ -67,7 +67,7 @@ </execute-stage> <execute-stage service="TEZ" component="TEZ_CLIENT" title="Check Tez Tarball"> - <task xsi:type="execute" hosts="any"> <!-- hosts="any" --> + <task xsi:type="execute" hosts="any"> <script>scripts/pre_upgrade.py</script> <function>prepare</function> </task> http://git-wip-us.apache.org/repos/asf/ambari/blob/0aeb3771/ambari-server/src/test/java/org/apache/ambari/server/checks/ServicesUpCheckTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/checks/ServicesUpCheckTest.java b/ambari-server/src/test/java/org/apache/ambari/server/checks/ServicesUpCheckTest.java index c59ded4..87cb8a9 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/checks/ServicesUpCheckTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/checks/ServicesUpCheckTest.java @@ -17,27 +17,38 @@ */ package org.apache.ambari.server.checks; -import java.util.Collections; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import com.google.inject.Provider; import org.apache.ambari.server.api.services.AmbariMetaInfo; import org.apache.ambari.server.controller.PrereqCheckRequest; +import org.apache.ambari.server.orm.models.HostComponentSummary; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.state.Service; +import org.apache.ambari.server.state.ServiceComponent; import org.apache.ambari.server.state.StackId; import org.apache.ambari.server.state.State; import org.apache.ambari.server.state.stack.PrereqCheckStatus; import org.apache.ambari.server.state.stack.PrerequisiteCheck; import org.junit.Assert; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; -import com.google.inject.Provider; /** * Unit tests for ServicesUpCheck * */ +@RunWith(PowerMockRunner.class) // Allow mocking static methods +@PrepareForTest(HostComponentSummary.class) // This class has a static method that will be mocked public class ServicesUpCheckTest { private final Clusters clusters = Mockito.mock(Clusters.class); @@ -53,6 +64,8 @@ public class ServicesUpCheckTest { @Test public void testPerform() throws Exception { + PowerMockito.mockStatic(HostComponentSummary.class); + final ServicesUpCheck servicesUpCheck = new ServicesUpCheck(); servicesUpCheck.clustersProvider = new Provider<Clusters>() { @@ -74,18 +87,136 @@ public class ServicesUpCheckTest { Mockito.when(cluster.getClusterId()).thenReturn(1L); Mockito.when(cluster.getCurrentStackVersion()).thenReturn(new StackId("HDP", "2.2")); Mockito.when(clusters.getCluster("cluster")).thenReturn(cluster); - final Service service = Mockito.mock(Service.class); - Mockito.when(cluster.getServices()).thenReturn(Collections.singletonMap("service", service)); - Mockito.when(service.isClientOnlyService()).thenReturn(false); - Mockito.when(service.getDesiredState()).thenReturn(State.UNKNOWN); + final Service hdfsService = Mockito.mock(Service.class); + final Service tezService = Mockito.mock(Service.class); + final Service amsService = Mockito.mock(Service.class); + + HashMap<String, Service> clusterServices = new HashMap<String, Service>(); + clusterServices.put("HDFS", hdfsService); + clusterServices.put("TEZ", tezService); + clusterServices.put("AMBARI_METRICS", amsService); + + Mockito.when(hdfsService.getName()).thenReturn("HDFS"); + Mockito.when(tezService.getName()).thenReturn("TEZ"); + Mockito.when(amsService.getName()).thenReturn("AMBARI_METRICS"); + + Mockito.when(hdfsService.isClientOnlyService()).thenReturn(false); + Mockito.when(tezService.isClientOnlyService()).thenReturn(true); + Mockito.when(amsService.isClientOnlyService()).thenReturn(false); + + Mockito.when(cluster.getServices()).thenReturn(clusterServices); + + + // Put Components inside Services + // HDFS + Map<String, ServiceComponent> hdfsComponents = new HashMap<String, ServiceComponent>(); + + ServiceComponent nameNode = Mockito.mock(ServiceComponent.class); + Mockito.when(nameNode.getName()).thenReturn("NAMENODE"); + Mockito.when(nameNode.isClientComponent()).thenReturn(false); + Mockito.when(nameNode.isVersionAdvertised()).thenReturn(true); + + ServiceComponent dataNode = Mockito.mock(ServiceComponent.class); + Mockito.when(dataNode.getName()).thenReturn("DATANODE"); + Mockito.when(dataNode.isClientComponent()).thenReturn(false); + Mockito.when(dataNode.isVersionAdvertised()).thenReturn(true); + + ServiceComponent zkfc = Mockito.mock(ServiceComponent.class); + Mockito.when(zkfc.getName()).thenReturn("ZKFC"); + Mockito.when(zkfc.isClientComponent()).thenReturn(false); + Mockito.when(zkfc.isVersionAdvertised()).thenReturn(false); + + hdfsComponents.put("NAMENODE", nameNode); + hdfsComponents.put("DATANODE", dataNode); + hdfsComponents.put("ZKFC", zkfc); + + Mockito.when(hdfsService.getServiceComponents()).thenReturn(hdfsComponents); + + // TEZ + Map<String, ServiceComponent> tezComponents = new HashMap<String, ServiceComponent>(); + + ServiceComponent tezClient = Mockito.mock(ServiceComponent.class); + Mockito.when(tezClient.getName()).thenReturn("TEZ_CLIENT"); + Mockito.when(tezClient.isClientComponent()).thenReturn(true); + Mockito.when(tezClient.isVersionAdvertised()).thenReturn(true); + + tezComponents.put("TEZ_CLIENT", tezClient); + + Mockito.when(tezService.getServiceComponents()).thenReturn(tezComponents); + + // AMS + Map<String, ServiceComponent> amsComponents = new HashMap<String, ServiceComponent>(); + + ServiceComponent metricsCollector = Mockito.mock(ServiceComponent.class); + Mockito.when(metricsCollector.getName()).thenReturn("METRICS_COLLECTOR"); + Mockito.when(metricsCollector.isClientComponent()).thenReturn(false); + Mockito.when(metricsCollector.isVersionAdvertised()).thenReturn(false); + + ServiceComponent metricsMonitor = Mockito.mock(ServiceComponent.class); + Mockito.when(metricsMonitor.getName()).thenReturn("METRICS_MONITOR"); + Mockito.when(metricsMonitor.isClientComponent()).thenReturn(false); + Mockito.when(metricsMonitor.isVersionAdvertised()).thenReturn(false); + + amsComponents.put("METRICS_COLLECTOR", metricsCollector); + amsComponents.put("METRICS_MONITOR", metricsMonitor); + + Mockito.when(amsService.getServiceComponents()).thenReturn(amsComponents); + + final HostComponentSummary hcsNameNode = Mockito.mock(HostComponentSummary.class); + final HostComponentSummary hcsDataNode = Mockito.mock(HostComponentSummary.class); + final HostComponentSummary hcsZKFC = Mockito.mock(HostComponentSummary.class); + final HostComponentSummary hcsTezClient = Mockito.mock(HostComponentSummary.class); + final HostComponentSummary hcsMetricsCollector = Mockito.mock(HostComponentSummary.class); + final HostComponentSummary hcsMetricsMonitor = Mockito.mock(HostComponentSummary.class); + + List<HostComponentSummary> allHostComponentSummaries = new ArrayList<HostComponentSummary>(); + allHostComponentSummaries.add(hcsNameNode); + allHostComponentSummaries.add(hcsDataNode); + allHostComponentSummaries.add(hcsZKFC); + allHostComponentSummaries.add(hcsTezClient); + allHostComponentSummaries.add(hcsMetricsCollector); + allHostComponentSummaries.add(hcsMetricsMonitor); + + // Mock the static method + Mockito.when(HostComponentSummary.getHostComponentSummaries("HDFS", "NAMENODE")).thenReturn(new ArrayList<HostComponentSummary>(){{ add(hcsNameNode); }}); + Mockito.when(HostComponentSummary.getHostComponentSummaries("HDFS", "DATANODE")).thenReturn(new ArrayList<HostComponentSummary>(){{ add(hcsDataNode); }}); + Mockito.when(HostComponentSummary.getHostComponentSummaries("HDFS", "ZKFC")).thenReturn(new ArrayList<HostComponentSummary>(){{ add(hcsZKFC); }}); + Mockito.when(HostComponentSummary.getHostComponentSummaries("TEZ", "TEZ_CLIENT")).thenReturn(new ArrayList<HostComponentSummary>(){{ add(hcsTezClient); }}); + Mockito.when(HostComponentSummary.getHostComponentSummaries("AMBARI_METRICS", "METRICS_COLLECTOR")).thenReturn(new ArrayList<HostComponentSummary>(){{ add(hcsMetricsCollector); }}); + Mockito.when(HostComponentSummary.getHostComponentSummaries("AMBARI_METRICS", "METRICS_MONITOR")).thenReturn(new ArrayList<HostComponentSummary>(){{ add(hcsMetricsMonitor); }}); + + // Case 1. Initialize with good values + for (HostComponentSummary hcs : allHostComponentSummaries) { + Mockito.when(hcs.getDesiredState()).thenReturn(State.INSTALLED); + Mockito.when(hcs.getCurrentState()).thenReturn(State.STARTED); + } PrerequisiteCheck check = new PrerequisiteCheck(null, null); servicesUpCheck.perform(check, new PrereqCheckRequest("cluster")); - Assert.assertEquals(PrereqCheckStatus.FAIL, check.getStatus()); - Mockito.when(service.getDesiredState()).thenReturn(State.STARTED); + // Case 2. Change some desired states to STARTED, should still pass + Mockito.when(hcsNameNode.getDesiredState()).thenReturn(State.STARTED); + Mockito.when(hcsDataNode.getDesiredState()).thenReturn(State.STARTED); + check = new PrerequisiteCheck(null, null); servicesUpCheck.perform(check, new PrereqCheckRequest("cluster")); Assert.assertEquals(PrereqCheckStatus.PASS, check.getStatus()); + + // Case 3. Ensure that ZKFC and AMS are ignored even if their current state is not STARTED + Mockito.when(hcsZKFC.getCurrentState()).thenReturn(State.INSTALLED); + Mockito.when(hcsMetricsCollector.getCurrentState()).thenReturn(State.INSTALLED); + Mockito.when(hcsMetricsMonitor.getCurrentState()).thenReturn(State.INSTALLED); + + check = new PrerequisiteCheck(null, null); + servicesUpCheck.perform(check, new PrereqCheckRequest("cluster")); + Assert.assertEquals(PrereqCheckStatus.PASS, check.getStatus()); + + // Case 4. Change HDFS current states to INSTALLED, should fail. + Mockito.when(hcsNameNode.getCurrentState()).thenReturn(State.INSTALLED); + Mockito.when(hcsDataNode.getCurrentState()).thenReturn(State.INSTALLED); + + check = new PrerequisiteCheck(null, null); + servicesUpCheck.perform(check, new PrereqCheckRequest("cluster")); + Assert.assertEquals(PrereqCheckStatus.FAIL, check.getStatus()); } }
