Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 65468200CC9 for ; Mon, 17 Jul 2017 18:20:22 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 639AE1651F3; Mon, 17 Jul 2017 16:20:22 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 098BA1651DF for ; Mon, 17 Jul 2017 18:20:20 +0200 (CEST) Received: (qmail 47832 invoked by uid 500); 17 Jul 2017 16:20:20 -0000 Mailing-List: contact commits-help@ambari.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: ambari-dev@ambari.apache.org Delivered-To: mailing list commits@ambari.apache.org Received: (qmail 47807 invoked by uid 99); 17 Jul 2017 16:20:20 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 17 Jul 2017 16:20:20 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id A2957F2183; Mon, 17 Jul 2017 16:20:19 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: jonathanhurley@apache.org To: commits@ambari.apache.org Date: Mon, 17 Jul 2017 16:20:23 -0000 Message-Id: <6b366a7e46f1416b85f866a0e5d995ab@git.apache.org> In-Reply-To: <60e8daf89e324c449726dd25926781e1@git.apache.org> References: <60e8daf89e324c449726dd25926781e1@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [05/26] ambari git commit: AMBARI-21436 - Add a Prerequisite Check To Ensure that the Target Stack Has All Existing Components (jonathanhurley) archived-at: Mon, 17 Jul 2017 16:20:22 -0000 AMBARI-21436 - Add a Prerequisite Check To Ensure that the Target Stack Has All Existing Components (jonathanhurley) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/113b381e Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/113b381e Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/113b381e Branch: refs/heads/branch-feature-AMBARI-21348 Commit: 113b381ecc530e7b1daf9a4cd7e546c1631df451 Parents: 7dbcb75 Author: Jonathan Hurley Authored: Thu Jul 13 15:59:45 2017 -0400 Committer: Jonathan Hurley Committed: Thu Jul 13 17:34:26 2017 -0400 ---------------------------------------------------------------------- .../ambari/server/checks/CheckDescription.java | 38 ++- .../checks/ComponentsExistInRepoCheck.java | 142 ++++++++ .../org/apache/ambari/server/state/Host.java | 4 +- .../ambari/server/state/host/HostImpl.java | 29 +- .../checks/ComponentExistsInRepoCheckTest.java | 329 +++++++++++++++++++ 5 files changed, 514 insertions(+), 28 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/113b381e/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 2be42fc..640de58 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 @@ -272,17 +272,17 @@ public class CheckDescription { "After upgrading, Atlas can be reinstalled").build()); public static CheckDescription SERVICE_PRESENCE_CHECK = new CheckDescription("SERVICE_PRESENCE_CHECK", - PrereqCheckType.SERVICE, - "Service Is Not Supported For Upgrades", - new ImmutableMap.Builder() - .put(AbstractCheckDescriptor.DEFAULT, - "The %s service is currently installed on the cluster. " + - "This service does not support upgrades and must be removed before the upgrade can continue. " + - "After upgrading, %s can be reinstalled") - .put(ServicePresenceCheck.KEY_SERVICE_REMOVED, - "The %s service is currently installed on the cluster. " + - "This service is removed from the new release and must be removed before the upgrade can continue. " + - "After upgrading, %s can be installed").build()); + PrereqCheckType.SERVICE, + "Service Is Not Supported For Upgrades", + new ImmutableMap.Builder() + .put(AbstractCheckDescriptor.DEFAULT, + "The %s service is currently installed on the cluster. " + + "This service does not support upgrades and must be removed before the upgrade can continue. " + + "After upgrading, %s can be reinstalled") + .put(ServicePresenceCheck.KEY_SERVICE_REMOVED, + "The %s service is currently installed on the cluster. " + + "This service is removed from the new release and must be removed before the upgrade can continue. " + + "After upgrading, %s can be installed").build()); public static CheckDescription RANGER_SERVICE_AUDIT_DB_CHECK = new CheckDescription("RANGER_SERVICE_AUDIT_DB_CHECK", PrereqCheckType.SERVICE, @@ -325,17 +325,23 @@ public class CheckDescription { PrereqCheckType.SERVICE, "Change Ranger SSL configuration path for Keystore and Truststore.", new ImmutableMap.Builder() - .put(AbstractCheckDescriptor.DEFAULT, - "As Ranger is SSL enabled, Ranger SSL configurations will need to be changed from default value of /etc/ranger/*/conf folder to /etc/ranger/security. " + - "Since the certificates/keystores/truststores in this path may affect the upgrade/downgrade process, it is recommended to manually move the certificates/keystores/truststores out of the conf folders and change the appropriate config values before proceeding.").build()); + .put(AbstractCheckDescriptor.DEFAULT, + "As Ranger is SSL enabled, Ranger SSL configurations will need to be changed from default value of /etc/ranger/*/conf folder to /etc/ranger/security. " + + "Since the certificates/keystores/truststores in this path may affect the upgrade/downgrade process, it is recommended to manually move the certificates/keystores/truststores out of the conf folders and change the appropriate config values before proceeding.").build()); public static CheckDescription JAVA_VERSION = new CheckDescription("JAVA_VERSION", PrereqCheckType.CLUSTER, "Verify Java version requirement", new ImmutableMap.Builder() .put(AbstractCheckDescriptor.DEFAULT, "Ambari requires JDK with minimum version %s. Reconfigure Ambari with a JDK that meets the version requirement.") - .build() - ); + .build()); + + public static CheckDescription COMPONENTS_EXIST_IN_TARGET_REPO = new CheckDescription("COMPONENTS_EXIST_IN_TARGET_REPO", + PrereqCheckType.CLUSTER, + "Verify Cluster Components Exist In Target Repository", + new ImmutableMap.Builder() + .put(AbstractCheckDescriptor.DEFAULT, "The following components do not exist in the target repository's stack. They must be removed from the cluster before upgrading.") + .build()); private String m_name; private PrereqCheckType m_type; http://git-wip-us.apache.org/repos/asf/ambari/blob/113b381e/ambari-server/src/main/java/org/apache/ambari/server/checks/ComponentsExistInRepoCheck.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/ComponentsExistInRepoCheck.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/ComponentsExistInRepoCheck.java new file mode 100644 index 0000000..d60433d --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/ComponentsExistInRepoCheck.java @@ -0,0 +1,142 @@ +/* + * 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.checks; + +import java.text.MessageFormat; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.ambari.annotations.Experimental; +import org.apache.ambari.annotations.ExperimentalFeature; +import org.apache.ambari.server.AmbariException; +import org.apache.ambari.server.StackAccessException; +import org.apache.ambari.server.controller.PrereqCheckRequest; +import org.apache.ambari.server.state.Cluster; +import org.apache.ambari.server.state.ComponentInfo; +import org.apache.ambari.server.state.Service; +import org.apache.ambari.server.state.ServiceComponent; +import org.apache.ambari.server.state.ServiceInfo; +import org.apache.ambari.server.state.StackId; +import org.apache.ambari.server.state.stack.PrereqCheckStatus; +import org.apache.ambari.server.state.stack.PrerequisiteCheck; +import org.apache.ambari.server.state.stack.upgrade.UpgradeType; +import org.apache.commons.lang.StringUtils; + +import com.google.inject.Singleton; + +/** + * The {@link ComponentsExistInRepoCheck} is used to determine if any of the + * components scheduled for upgrade do not exist in the target repository or + * stack. + */ +@Singleton +@UpgradeCheck( + group = UpgradeCheckGroup.TOPOLOGY, + required = { UpgradeType.ROLLING, UpgradeType.NON_ROLLING, UpgradeType.HOST_ORDERED }) +public class ComponentsExistInRepoCheck extends AbstractCheckDescriptor { + + /** + * Constructor. + */ + public ComponentsExistInRepoCheck() { + super(CheckDescription.COMPONENTS_EXIST_IN_TARGET_REPO); + } + + @Override + public void perform(PrerequisiteCheck prerequisiteCheck, PrereqCheckRequest request) + throws AmbariException { + final String clusterName = request.getClusterName(); + final Cluster cluster = clustersProvider.get().getCluster(clusterName); + StackId sourceStack = request.getSourceStackId(); + StackId targetStack = request.getTargetStackId(); + + Set failedServices = new TreeSet<>(); + Set failedComponents = new TreeSet<>(); + + @Experimental( + feature = ExperimentalFeature.PATCH_UPGRADES, + comment = "Assumes all service participate in the upgrade") + Map servicesInUpgrade = cluster.getServices(); + for (String serviceName : servicesInUpgrade.keySet()) { + try { + ServiceInfo serviceInfo = ambariMetaInfo.get().getService(targetStack.getStackName(), + targetStack.getStackVersion(), serviceName); + + if (serviceInfo.isDeleted() || !serviceInfo.isValid()) { + failedServices.add(serviceName); + continue; + } + + Service service = servicesInUpgrade.get(serviceName); + Map componentsInUpgrade = service.getServiceComponents(); + for (String componentName : componentsInUpgrade.keySet()) { + try { + ComponentInfo componentInfo = ambariMetaInfo.get().getComponent( + targetStack.getStackName(), targetStack.getStackVersion(), serviceName, + componentName); + + // if this component isn't included in the upgrade, then skip it + if (!componentInfo.isVersionAdvertised()) { + continue; + } + + if (componentInfo.isDeleted()) { + failedComponents.add(componentName); + } + + } catch (StackAccessException stackAccessException) { + failedComponents.add(componentName); + } + } + } catch (StackAccessException stackAccessException) { + failedServices.add(serviceName); + } + } + + if( failedServices.isEmpty() && failedComponents.isEmpty() ){ + prerequisiteCheck.setStatus(PrereqCheckStatus.PASS); + return; + } + + LinkedHashSet failedOn = new LinkedHashSet<>(); + failedOn.addAll(failedServices); + failedOn.addAll(failedComponents); + + prerequisiteCheck.setFailedOn(failedOn); + prerequisiteCheck.setStatus(PrereqCheckStatus.FAIL); + + String message = "The following {0} exist in {1} but are not included in {2}. They must be removed before upgrading."; + String messageFragment = ""; + if (!failedServices.isEmpty()) { + messageFragment = "services"; + } + + if( !failedComponents.isEmpty() ){ + if(!StringUtils.isEmpty(messageFragment)){ + messageFragment += " and "; + } + + messageFragment += "components"; + } + + message = MessageFormat.format(message, messageFragment, sourceStack, targetStack); + prerequisiteCheck.setFailReason(message); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/113b381e/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java index 241659a..78587af 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Host.java @@ -395,7 +395,9 @@ public interface Host extends Comparable { List getAllHostVersions(); /** - * Gets whether this host has components which advertise their version. + * Gets whether this host has components which advertise their version for the + * given stack. If the components on the host do not exist in the given stack, + * then it is assumed they do not advertise their version. * * @param stackId * the version of the stack to use when checking version http://git-wip-us.apache.org/repos/asf/ambari/blob/113b381e/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java index 328fe22..42ec945 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/host/HostImpl.java @@ -30,6 +30,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.HostNotFoundException; +import org.apache.ambari.server.StackAccessException; import org.apache.ambari.server.agent.AgentEnv; import org.apache.ambari.server.agent.DiskInfo; import org.apache.ambari.server.agent.HostInfo; @@ -148,7 +149,7 @@ public class HostImpl implements Host { private long lastHeartbeatTime = 0L; private AgentEnv lastAgentEnv = null; - private List disksInfo = new CopyOnWriteArrayList(); + private List disksInfo = new CopyOnWriteArrayList<>(); private RecoveryReport recoveryReport = new RecoveryReport(); private Integer currentPingPort = null; @@ -481,7 +482,7 @@ public class HostImpl implements Host { // FIXME add all other information into host attributes setAgentVersion(new AgentVersion(hostInfo.getAgentUserId())); - Map attrs = new HashMap(); + Map attrs = new HashMap<>(); if (hostInfo.getHardwareIsa() != null) { attrs.put(HARDWAREISA, hostInfo.getHardwareIsa()); } @@ -828,7 +829,7 @@ public class HostImpl implements Host { Map hostAttrs = gson.fromJson(hostEntity.getHostAttributes(), hostAttributesType); if (hostAttrs == null) { - hostAttrs = new ConcurrentHashMap(); + hostAttrs = new ConcurrentHashMap<>(); } hostAttrs.putAll(hostAttributes); @@ -1024,7 +1025,7 @@ public class HostImpl implements Host { @Override public Map getDesiredConfigs(long clusterId) { - Map map = new HashMap(); + Map map = new HashMap<>(); for (HostConfigMapping e : hostConfigMappingDAO.findSelected( clusterId, getHostId())) { @@ -1045,10 +1046,10 @@ public class HostImpl implements Host { @Override public Map getDesiredHostConfigs(Cluster cluster, Map clusterDesiredConfigs) throws AmbariException { - Map hostConfigMap = new HashMap(); + Map hostConfigMap = new HashMap<>(); if( null == cluster ){ - clusterDesiredConfigs = new HashMap(); + clusterDesiredConfigs = new HashMap<>(); } // per method contract, fetch if not supplied @@ -1173,12 +1174,18 @@ public class HostImpl implements Host { HostEntity hostEntity = getHostEntity(); for (HostComponentStateEntity componentState : hostEntity.getHostComponentStateEntities()) { - ComponentInfo component = ambariMetaInfo.getComponent(stackId.getStackName(), - stackId.getStackVersion(), componentState.getServiceName(), - componentState.getComponentName()); + try { + ComponentInfo component = ambariMetaInfo.getComponent(stackId.getStackName(), + stackId.getStackVersion(), componentState.getServiceName(), + componentState.getComponentName()); - if (component.isVersionAdvertised()) { - return true; + if (component.isVersionAdvertised()) { + return true; + } + } catch( StackAccessException stackAccessException ){ + LOG.info("{}/{} does not exist in {} and will not advertise its version for that stack.", + componentState.getServiceName(), componentState.getComponentName(), + stackId.getStackId()); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/113b381e/ambari-server/src/test/java/org/apache/ambari/server/checks/ComponentExistsInRepoCheckTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/checks/ComponentExistsInRepoCheckTest.java b/ambari-server/src/test/java/org/apache/ambari/server/checks/ComponentExistsInRepoCheckTest.java new file mode 100644 index 0000000..76e8cc9 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/checks/ComponentExistsInRepoCheckTest.java @@ -0,0 +1,329 @@ +/** + * 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.checks; + +import static org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.expect; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.ambari.server.StackAccessException; +import org.apache.ambari.server.api.services.AmbariMetaInfo; +import org.apache.ambari.server.controller.PrereqCheckRequest; +import org.apache.ambari.server.state.Cluster; +import org.apache.ambari.server.state.Clusters; +import org.apache.ambari.server.state.ComponentInfo; +import org.apache.ambari.server.state.Service; +import org.apache.ambari.server.state.ServiceComponent; +import org.apache.ambari.server.state.ServiceInfo; +import org.apache.ambari.server.state.StackId; +import org.apache.ambari.server.state.stack.PrereqCheckStatus; +import org.apache.ambari.server.state.stack.PrerequisiteCheck; +import org.apache.commons.lang.StringUtils; +import org.easymock.EasyMockSupport; +import org.easymock.Mock; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.google.inject.Provider; + +/** + * Tests for {@link ComponentsExistInRepoCheck} + */ +public class ComponentExistsInRepoCheckTest extends EasyMockSupport { + + private final ComponentsExistInRepoCheck m_check = new ComponentsExistInRepoCheck(); + + @Mock + private Clusters m_clusters; + + @Mock + private Cluster m_cluster; + + // pick two stacks which have different services + private final StackId SOURCE_STACK = new StackId("HDP", "0.1"); + private final StackId TARGET_STACK = new StackId("HDP", "2.2.0"); + + private final Map CLUSTER_SERVICES = new HashMap<>(); + private final Map FOO_SERVICE_COMPONENTS = new HashMap<>(); + private final Map ZK_SERVICE_COMPONENTS = new HashMap<>(); + + @Mock + private AmbariMetaInfo m_ambariMetaInfo; + + @Mock + private Service m_fooService; + + @Mock + private Service m_zookeeperService; + + @Mock + private ServiceInfo m_fooInfo; + + @Mock + private ServiceInfo m_zookeeperInfo; + + @Mock + private ComponentInfo m_fooComponentInfo; + + @Mock + private ComponentInfo m_zookeeperServerInfo; + + @Mock + private ServiceComponent m_fooComponent; + + @Mock + private ServiceComponent m_zookeeperServer; + + @Before + public void before() throws Exception { + + EasyMockSupport.injectMocks(this); + + m_check.clustersProvider = new Provider() { + @Override + public Clusters get() { + return m_clusters; + } + }; + + m_check.ambariMetaInfo = new Provider() { + @Override + public AmbariMetaInfo get() { + return m_ambariMetaInfo; + } + }; + + expect(m_cluster.getServices()).andReturn(CLUSTER_SERVICES).atLeastOnce(); + expect(m_clusters.getCluster((String) anyObject())).andReturn(m_cluster).anyTimes(); + + ZK_SERVICE_COMPONENTS.put("ZOOKEEPER_SERVER", m_zookeeperServer); + FOO_SERVICE_COMPONENTS.put("FOO_COMPONENT", m_fooComponent); + + expect(m_zookeeperService.getServiceComponents()).andReturn(ZK_SERVICE_COMPONENTS).anyTimes(); + expect(m_fooService.getServiceComponents()).andReturn(FOO_SERVICE_COMPONENTS).anyTimes(); + + expect(m_zookeeperInfo.getComponentByName("ZOOKEEPER_SERVER")).andReturn( + m_zookeeperServerInfo).anyTimes(); + + expect(m_fooInfo.getComponentByName("FOO_COMPONENT")).andReturn(m_fooComponentInfo).anyTimes(); + + expect(m_ambariMetaInfo.getService(TARGET_STACK.getStackName(), TARGET_STACK.getStackVersion(), + "ZOOKEEPER")).andReturn(m_zookeeperInfo).anyTimes(); + + expect(m_ambariMetaInfo.getComponent(TARGET_STACK.getStackName(), + TARGET_STACK.getStackVersion(), "ZOOKEEPER", "ZOOKEEPER_SERVER")).andReturn( + m_zookeeperServerInfo).anyTimes(); + } + + /** + * Tests that the check passes when services and components exist. + * + * @throws Exception + */ + @Test + public void testCheckPassesWhenServicAndComponentsExist() throws Exception { + PrerequisiteCheck check = new PrerequisiteCheck(CheckDescription.COMPONENTS_EXIST_IN_TARGET_REPO, "c1"); + PrereqCheckRequest request = new PrereqCheckRequest("cluster"); + request.setSourceStackId(SOURCE_STACK); + request.setTargetStackId(TARGET_STACK); + + CLUSTER_SERVICES.put("ZOOKEEPER", m_zookeeperService); + expect(m_zookeeperInfo.isValid()).andReturn(true).atLeastOnce(); + expect(m_zookeeperInfo.isDeleted()).andReturn(false).atLeastOnce(); + expect(m_zookeeperServerInfo.isVersionAdvertised()).andReturn(true).atLeastOnce(); + expect(m_zookeeperServerInfo.isDeleted()).andReturn(false).atLeastOnce(); + + replayAll(); + + Assert.assertTrue(m_check.isApplicable(request)); + + m_check.perform(check, request); + + Assert.assertEquals(PrereqCheckStatus.PASS, check.getStatus()); + Assert.assertTrue(StringUtils.isBlank(check.getFailReason())); + } + + /** + * Tests that the check passes when a service doesn't exist but isn't + * advertising its version. + * + * @throws Exception + */ + @Test + public void testCheckPassesWhenComponentNotAdvertisingVersion() throws Exception { + PrerequisiteCheck check = new PrerequisiteCheck(CheckDescription.COMPONENTS_EXIST_IN_TARGET_REPO, "c1"); + PrereqCheckRequest request = new PrereqCheckRequest("cluster"); + request.setSourceStackId(SOURCE_STACK); + request.setTargetStackId(TARGET_STACK); + + CLUSTER_SERVICES.put("FOO_SERVICE", m_fooService); + + expect(m_ambariMetaInfo.getService(TARGET_STACK.getStackName(), TARGET_STACK.getStackVersion(), + "FOO_SERVICE")).andReturn(m_fooInfo).anyTimes(); + + expect(m_ambariMetaInfo.getComponent(TARGET_STACK.getStackName(), + TARGET_STACK.getStackVersion(), "FOO_SERVICE", "FOO_COMPONENT")).andReturn( + m_fooComponentInfo).atLeastOnce(); + + expect(m_fooInfo.isValid()).andReturn(true).atLeastOnce(); + expect(m_fooInfo.isDeleted()).andReturn(false).atLeastOnce(); + expect(m_fooComponentInfo.isVersionAdvertised()).andReturn(false).atLeastOnce(); + expect(m_fooComponentInfo.isDeleted()).andReturn(true).atLeastOnce(); + + replayAll(); + + Assert.assertTrue(m_check.isApplicable(request)); + + m_check.perform(check, request); + + Assert.assertEquals(PrereqCheckStatus.PASS, check.getStatus()); + Assert.assertTrue(StringUtils.isBlank(check.getFailReason())); + } + + /** + * Tests that the check fails when the service exists but was deleted. + * + * @throws Exception + */ + @Test + public void testCheckFailsWhenServiceExistsButIsDeleted() throws Exception { + PrerequisiteCheck check = new PrerequisiteCheck(CheckDescription.COMPONENTS_EXIST_IN_TARGET_REPO, "c1"); + PrereqCheckRequest request = new PrereqCheckRequest("cluster"); + request.setSourceStackId(SOURCE_STACK); + request.setTargetStackId(TARGET_STACK); + + CLUSTER_SERVICES.put("ZOOKEEPER", m_zookeeperService); + expect(m_zookeeperInfo.isValid()).andReturn(true).atLeastOnce(); + expect(m_zookeeperInfo.isDeleted()).andReturn(true).atLeastOnce(); + + replayAll(); + + Assert.assertTrue(m_check.isApplicable(request)); + + m_check.perform(check, request); + + Assert.assertEquals(PrereqCheckStatus.FAIL, check.getStatus()); + Assert.assertTrue(check.getFailedOn().contains("ZOOKEEPER")); + } + + /** + * Tests that the check fails when the component exists but what deleted. + * + * @throws Exception + */ + @Test + public void testCheckFailsWhenComponentExistsButIsDeleted() throws Exception { + PrerequisiteCheck check = new PrerequisiteCheck(CheckDescription.COMPONENTS_EXIST_IN_TARGET_REPO, "c1"); + PrereqCheckRequest request = new PrereqCheckRequest("cluster"); + request.setSourceStackId(SOURCE_STACK); + request.setTargetStackId(TARGET_STACK); + + CLUSTER_SERVICES.put("ZOOKEEPER", m_zookeeperService); + expect(m_zookeeperInfo.isValid()).andReturn(true).atLeastOnce(); + expect(m_zookeeperInfo.isDeleted()).andReturn(false).atLeastOnce(); + expect(m_zookeeperServerInfo.isVersionAdvertised()).andReturn(true).atLeastOnce(); + expect(m_zookeeperServerInfo.isDeleted()).andReturn(true).atLeastOnce(); + + replayAll(); + + Assert.assertTrue(m_check.isApplicable(request)); + + m_check.perform(check, request); + + Assert.assertEquals(PrereqCheckStatus.FAIL, check.getStatus()); + Assert.assertTrue(check.getFailedOn().contains("ZOOKEEPER_SERVER")); + } + + /** + * Tests that the check fails when the component exists but what deleted. + * + * @throws Exception + */ + @Test + public void testCheckFailsWhenServiceIsMissing() throws Exception { + PrerequisiteCheck check = new PrerequisiteCheck( + CheckDescription.COMPONENTS_EXIST_IN_TARGET_REPO, "c1"); + PrereqCheckRequest request = new PrereqCheckRequest("cluster"); + request.setSourceStackId(SOURCE_STACK); + request.setTargetStackId(TARGET_STACK); + + CLUSTER_SERVICES.put("ZOOKEEPER", m_zookeeperService); + CLUSTER_SERVICES.put("FOO_SERVICE", m_fooService); + + expect(m_ambariMetaInfo.getService(TARGET_STACK.getStackName(), TARGET_STACK.getStackVersion(), + "FOO_SERVICE")).andThrow(new StackAccessException("")); + + expect(m_zookeeperInfo.isValid()).andReturn(true).atLeastOnce(); + expect(m_zookeeperInfo.isDeleted()).andReturn(false).atLeastOnce(); + expect(m_zookeeperServerInfo.isVersionAdvertised()).andReturn(true).atLeastOnce(); + expect(m_zookeeperServerInfo.isDeleted()).andReturn(false).atLeastOnce(); + + replayAll(); + + Assert.assertTrue(m_check.isApplicable(request)); + + m_check.perform(check, request); + + Assert.assertEquals(PrereqCheckStatus.FAIL, check.getStatus()); + Assert.assertTrue(check.getFailedOn().contains("FOO_SERVICE")); + } + + /** + * Tests that the check fails when the component exists but what deleted. + * + * @throws Exception + */ + @Test + public void testCheckFailsWhenComponentIsMissing() throws Exception { + PrerequisiteCheck check = new PrerequisiteCheck( + CheckDescription.COMPONENTS_EXIST_IN_TARGET_REPO, "c1"); + PrereqCheckRequest request = new PrereqCheckRequest("cluster"); + request.setSourceStackId(SOURCE_STACK); + request.setTargetStackId(TARGET_STACK); + + CLUSTER_SERVICES.put("FOO_SERVICE", m_fooService); + + expect(m_ambariMetaInfo.getService(TARGET_STACK.getStackName(), TARGET_STACK.getStackVersion(), + "FOO_SERVICE")).andReturn(m_fooInfo).anyTimes(); + + expect(m_ambariMetaInfo.getComponent(TARGET_STACK.getStackName(), + TARGET_STACK.getStackVersion(), "FOO_SERVICE", "FOO_COMPONENT")).andThrow( + new StackAccessException("")); + + expect(m_zookeeperInfo.isValid()).andReturn(true).atLeastOnce(); + expect(m_zookeeperInfo.isDeleted()).andReturn(false).atLeastOnce(); + expect(m_zookeeperServerInfo.isVersionAdvertised()).andReturn(true).atLeastOnce(); + expect(m_zookeeperServerInfo.isDeleted()).andReturn(false).atLeastOnce(); + + expect(m_fooInfo.isValid()).andReturn(true).atLeastOnce(); + expect(m_fooInfo.isDeleted()).andReturn(false).atLeastOnce(); + + replayAll(); + + Assert.assertTrue(m_check.isApplicable(request)); + + m_check.perform(check, request); + + Assert.assertEquals(PrereqCheckStatus.FAIL, check.getStatus()); + Assert.assertTrue(check.getFailedOn().contains("FOO_COMPONENT")); + } + +} \ No newline at end of file