You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by jo...@apache.org on 2017/07/18 15:02:58 UTC

[22/50] [abbrv] ambari git commit: AMBARI-21436 - Add a Prerequisite Check To Ensure that the Target Stack Has All Existing Components (jonathanhurley)

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-21450
Commit: 113b381ecc530e7b1daf9a4cd7e546c1631df451
Parents: 7dbcb75
Author: Jonathan Hurley <jh...@hortonworks.com>
Authored: Thu Jul 13 15:59:45 2017 -0400
Committer: Jonathan Hurley <jh...@hortonworks.com>
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<String, String>()
-        .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<String, String>()
+      .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<String, String>()
-            .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<String, String>()
         .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<String, String>()
+        .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<String> failedServices = new TreeSet<>();
+    Set<String> failedComponents = new TreeSet<>();
+
+    @Experimental(
+        feature = ExperimentalFeature.PATCH_UPGRADES,
+        comment = "Assumes all service participate in the upgrade")
+    Map<String, Service> 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<String, ServiceComponent> 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<String> 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<HostVersionEntity> 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<DiskInfo> disksInfo = new CopyOnWriteArrayList<DiskInfo>();
+  private List<DiskInfo> 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<String, String> attrs = new HashMap<String, String>();
+    Map<String, String> attrs = new HashMap<>();
     if (hostInfo.getHardwareIsa() != null) {
       attrs.put(HARDWAREISA, hostInfo.getHardwareIsa());
     }
@@ -828,7 +829,7 @@ public class HostImpl implements Host {
     Map<String, String> hostAttrs = gson.fromJson(hostEntity.getHostAttributes(), hostAttributesType);
 
     if (hostAttrs == null) {
-      hostAttrs = new ConcurrentHashMap<String, String>();
+      hostAttrs = new ConcurrentHashMap<>();
     }
 
     hostAttrs.putAll(hostAttributes);
@@ -1024,7 +1025,7 @@ public class HostImpl implements Host {
 
   @Override
   public Map<String, DesiredConfig> getDesiredConfigs(long clusterId) {
-    Map<String, DesiredConfig> map = new HashMap<String, DesiredConfig>();
+    Map<String, DesiredConfig> map = new HashMap<>();
 
     for (HostConfigMapping e : hostConfigMappingDAO.findSelected(
         clusterId, getHostId())) {
@@ -1045,10 +1046,10 @@ public class HostImpl implements Host {
   @Override
   public Map<String, HostConfig> getDesiredHostConfigs(Cluster cluster,
       Map<String, DesiredConfig> clusterDesiredConfigs) throws AmbariException {
-    Map<String, HostConfig> hostConfigMap = new HashMap<String, HostConfig>();
+    Map<String, HostConfig> hostConfigMap = new HashMap<>();
 
     if( null == cluster ){
-      clusterDesiredConfigs = new HashMap<String, DesiredConfig>();
+      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<String, Service> CLUSTER_SERVICES = new HashMap<>();
+  private final Map<String, ServiceComponent> FOO_SERVICE_COMPONENTS = new HashMap<>();
+  private final Map<String, ServiceComponent> 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<Clusters>() {
+      @Override
+      public Clusters get() {
+        return m_clusters;
+      }
+    };
+
+    m_check.ambariMetaInfo = new Provider<AmbariMetaInfo>() {
+      @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