You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sw...@apache.org on 2015/11/24 07:03:58 UTC

ambari git commit: AMBARI-14025. Deleting host from cluster does not work on blueprint deployed cluster. (swagle)

Repository: ambari
Updated Branches:
  refs/heads/branch-2.1.2 7b1ac0f0a -> 805f530b1


AMBARI-14025. Deleting host from cluster does not work on blueprint deployed cluster. (swagle)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/805f530b
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/805f530b
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/805f530b

Branch: refs/heads/branch-2.1.2
Commit: 805f530b16ee33a62d874836aa0c50dccc44815e
Parents: 7b1ac0f
Author: Siddharth Wagle <sw...@hortonworks.com>
Authored: Mon Nov 23 20:32:27 2015 -0800
Committer: Siddharth Wagle <sw...@hortonworks.com>
Committed: Mon Nov 23 20:33:10 2015 -0800

----------------------------------------------------------------------
 .../actionmanager/ActionDBAccessorImpl.java     | 54 +++++++++-----
 .../server/actionmanager/ActionManager.java     |  3 +-
 .../ambari/server/agent/HeartBeatHandler.java   | 15 +++-
 .../controller/internal/CalculatedStatus.java   |  6 ++
 .../internal/HostResourceProvider.java          |  3 +-
 .../internal/RequestResourceProvider.java       |  8 +-
 .../internal/StageResourceProvider.java         |  8 +-
 .../server/orm/dao/HostRoleCommandDAO.java      |  3 +-
 .../server/state/cluster/ClustersImpl.java      | 28 +++++--
 .../internal/RequestResourceProviderTest.java   | 78 +++++++++++++++++---
 10 files changed, 159 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/805f530b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java
index 30da833..093976a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java
@@ -17,21 +17,20 @@
  */
 package org.apache.ambari.server.actionmanager;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import com.google.inject.persist.Transactional;
 import org.apache.ambari.annotations.Experimental;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.agent.CommandReport;
 import org.apache.ambari.server.agent.ExecutionCommand;
 import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.events.HostRemovedEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.dao.ClusterDAO;
 import org.apache.ambari.server.orm.dao.ExecutionCommandDAO;
 import org.apache.ambari.server.orm.dao.HostDAO;
@@ -56,13 +55,15 @@ import org.apache.ambari.server.utils.ParallelLoopResult;
 import org.apache.ambari.server.utils.StageUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
-import com.google.inject.persist.Transactional;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 @Singleton
 public class ActionDBAccessorImpl implements ActionDBAccessor {
@@ -113,13 +114,15 @@ public class ActionDBAccessorImpl implements ActionDBAccessor {
   private long cacheLimit; //may be exceeded to store tasks from one request
 
   @Inject
-  public ActionDBAccessorImpl(@Named("executionCommandCacheSize") long cacheLimit) {
+  public ActionDBAccessorImpl(@Named("executionCommandCacheSize") long cacheLimit,
+                              AmbariEventPublisher eventPublisher) {
 
     this.cacheLimit = cacheLimit;
     hostRoleCommandCache = CacheBuilder.newBuilder().
         expireAfterAccess(5, TimeUnit.MINUTES).
         build();
 
+    eventPublisher.register(this);
   }
 
   @Inject
@@ -218,7 +221,7 @@ public class ActionDBAccessorImpl implements ActionDBAccessor {
   @Experimental
   public List<Stage> getStagesInProgress() {
     List<StageEntity> stageEntities = stageDAO.findByCommandStatuses(
-        HostRoleStatus.IN_PROGRESS_STATUSES);
+      HostRoleStatus.IN_PROGRESS_STATUSES);
 
     // experimentally enable parallel stage processing
     @Experimental
@@ -681,7 +684,7 @@ public class ActionDBAccessorImpl implements ActionDBAccessor {
     }
 
     return hostRoleCommandDAO.getRequestsByTaskStatus(taskStatuses, maxResults,
-        ascOrder);
+      ascOrder);
   }
 
   @Override
@@ -717,4 +720,15 @@ public class ActionDBAccessorImpl implements ActionDBAccessor {
 
     hostRoleCommandDAO.mergeAll(tasks);
   }
+
+  /**
+   * Invalidate cached HostRoleCommands if a host is deleted.
+   * @param event @HostRemovedEvent
+   */
+  @Subscribe
+  public void invalidateCommandCacheOnHostRemove(HostRemovedEvent event) {
+    LOG.info("Invalidating command cache on host delete event." );
+    LOG.debug("HostRemovedEvent => " + event);
+    hostRoleCommandCache.invalidateAll();
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/805f530b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionManager.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionManager.java b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionManager.java
index 2524df8..f168ac6 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionManager.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionManager.java
@@ -69,8 +69,7 @@ public class ActionManager {
     this.db = db;
     scheduler = new ActionScheduler(schedulerSleepTime, actionTimeout, db,
         actionQueue, fsm, 2, hostsMap, unitOfWork, ambariEventPublisher, configuration);
-    requestCounter = new AtomicLong(
-        db.getLastPersistedRequestIdWhenInitialized());
+    requestCounter = new AtomicLong(db.getLastPersistedRequestIdWhenInitialized());
     this.requestFactory = requestFactory;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/805f530b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
index 7fcdac9..d8d9418 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java
@@ -199,7 +199,7 @@ public class HeartBeatHandler {
   public HeartBeatResponse handleHeartBeat(HeartBeat heartbeat)
       throws AmbariException {
     long now = System.currentTimeMillis();
-    if(heartbeat.getAgentEnv() != null && heartbeat.getAgentEnv().getHostHealth() != null) {
+    if (heartbeat.getAgentEnv() != null && heartbeat.getAgentEnv().getHostHealth() != null) {
       heartbeat.getAgentEnv().getHostHealth().setServerTimeStampAtReporting(now);
     }
 
@@ -229,7 +229,18 @@ public class HeartBeatHandler {
     response = new HeartBeatResponse();
     response.setResponseId(++currentResponseId);
 
-    Host hostObject = clusterFsm.getHost(hostname);
+    Host hostObject;
+    try {
+      hostObject = clusterFsm.getHost(hostname);
+    } catch (HostNotFoundException e) {
+      LOG.error("Host: {} not found. Agent is still heartbeating.", hostname);
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Host associated with the agent heratbeat might have been " +
+          "deleted", e);
+      }
+      // For now return empty response with only response id.
+      return response;
+    }
 
     if (hostObject.getState().equals(HostState.HEARTBEAT_LOST)) {
       // After loosing heartbeat agent should reregister

http://git-wip-us.apache.org/repos/asf/ambari/blob/805f530b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/CalculatedStatus.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/CalculatedStatus.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/CalculatedStatus.java
index 55d91c7..26dc718 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/CalculatedStatus.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/CalculatedStatus.java
@@ -62,6 +62,12 @@ public class CalculatedStatus {
     this.percent = percent;
   }
 
+  /**
+   * Static factory method to get Status that represents a Completed state
+   */
+  public static CalculatedStatus getCompletedStatus() {
+    return new CalculatedStatus(HostRoleStatus.COMPLETED, 100.0);
+  }
 
   // ----- CalculatedStatus --------------------------------------------------
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/805f530b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
index 39d4040..ed1ca28 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostResourceProvider.java
@@ -764,8 +764,7 @@ public class HostResourceProvider extends AbstractControllerResourceProvider {
   }
 
 
-  protected void deleteHosts(Set<HostRequest> requests)
-      throws AmbariException {
+  protected void deleteHosts(Set<HostRequest> requests) throws AmbariException {
 
     AmbariManagementController controller = getManagementController();
     Clusters                   clusters   = controller.getClusters();

http://git-wip-us.apache.org/repos/asf/ambari/blob/805f530b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
index 911e3cd..061b27d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestResourceProvider.java
@@ -505,7 +505,13 @@ public class RequestResourceProvider extends AbstractControllerResourceProvider
     // get summaries from TopologyManager for logical requests
     summary.putAll(topologyManager.getStageSummaries(entity.getRequestId()));
 
-    CalculatedStatus status = CalculatedStatus.statusFromStageSummary(summary, summary.keySet());
+    CalculatedStatus status;
+    if (summary.isEmpty()) {
+      // Delete host might have cleared all HostRoleCommands
+      status = CalculatedStatus.getCompletedStatus();
+    } else {
+      status = CalculatedStatus.statusFromStageSummary(summary, summary.keySet());
+    }
 
     setResourceProperty(resource, REQUEST_STATUS_PROPERTY_ID, status.getStatus().toString(), requestedPropertyIds);
     setResourceProperty(resource, REQUEST_PROGRESS_PERCENT_ID, status.getPercent(), requestedPropertyIds);

http://git-wip-us.apache.org/repos/asf/ambari/blob/805f530b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StageResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StageResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StageResourceProvider.java
index d479bfe..492ac34 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StageResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/StageResourceProvider.java
@@ -294,7 +294,13 @@ public class StageResourceProvider extends AbstractControllerResourceProvider im
     setResourceProperty(resource, STAGE_START_TIME, startTime, requestedIds);
     setResourceProperty(resource, STAGE_END_TIME, endTime, requestedIds);
 
-    CalculatedStatus status = CalculatedStatus.statusFromStageSummary(summary, Collections.singleton(entity.getStageId()));
+    CalculatedStatus status;
+    if (summary.isEmpty()) {
+      // Delete host might have cleared all HostRoleCommands
+      status = CalculatedStatus.getCompletedStatus();
+    } else {
+      status = CalculatedStatus.statusFromStageSummary(summary, Collections.singleton(entity.getStageId()));
+    }
 
     setResourceProperty(resource, STAGE_PROGRESS_PERCENT, status.getPercent(), requestedIds);
     setResourceProperty(resource, STAGE_STATUS, status.getStatus().toString(), requestedIds);

http://git-wip-us.apache.org/repos/asf/ambari/blob/805f530b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostRoleCommandDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostRoleCommandDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostRoleCommandDAO.java
index f04c868..2797c48 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostRoleCommandDAO.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/HostRoleCommandDAO.java
@@ -120,8 +120,7 @@ public class HostRoleCommandDAO {
   @RequiresSession
   public List<HostRoleCommandEntity> findByHostId(Long hostId) {
     TypedQuery<HostRoleCommandEntity> query = entityManagerProvider.get().createNamedQuery(
-        "HostRoleCommandEntity.findByHostId",
-        HostRoleCommandEntity.class);
+        "HostRoleCommandEntity.findByHostId", HostRoleCommandEntity.class);
 
     query.setParameter("hostId", hostId);
     return daoUtils.selectList(query);

http://git-wip-us.apache.org/repos/asf/ambari/blob/805f530b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
index 4040c5f..cf03479 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClustersImpl.java
@@ -55,9 +55,11 @@ import org.apache.ambari.server.orm.dao.RequestOperationLevelDAO;
 import org.apache.ambari.server.orm.dao.ResourceTypeDAO;
 import org.apache.ambari.server.orm.dao.ServiceConfigDAO;
 import org.apache.ambari.server.orm.dao.StackDAO;
+import org.apache.ambari.server.orm.dao.TopologyLogicalTaskDAO;
 import org.apache.ambari.server.orm.entities.ClusterEntity;
 import org.apache.ambari.server.orm.entities.ClusterVersionEntity;
 import org.apache.ambari.server.orm.entities.HostEntity;
+import org.apache.ambari.server.orm.entities.HostRoleCommandEntity;
 import org.apache.ambari.server.orm.entities.PermissionEntity;
 import org.apache.ambari.server.orm.entities.PrivilegeEntity;
 import org.apache.ambari.server.orm.entities.ResourceEntity;
@@ -135,6 +137,8 @@ public class ClustersImpl implements Clusters {
   private AmbariMetaInfo ambariMetaInfo;
   @Inject
   private SecurityHelper securityHelper;
+  @Inject
+  private TopologyLogicalTaskDAO topologyLogicalTaskDAO;
 
   /**
    * Data access object for stacks.
@@ -708,10 +712,13 @@ public class ClustersImpl implements Clusters {
   @Override
   public void unmapHostFromCluster(String hostname, String clusterName) throws AmbariException {
     final Cluster cluster = getCluster(clusterName);
-    unmapHostFromClusters(hostname, new HashSet<Cluster>() {{ add(cluster); }});
+    unmapHostFromClusters(hostname, new HashSet<Cluster>() {{
+      add(cluster);
+    }});
   }
 
-  public void unmapHostFromClusters(String hostname, Set<Cluster> clusters) throws AmbariException {
+  @Transactional
+  void unmapHostFromClusters(String hostname, Set<Cluster> clusters) throws AmbariException {
     Host host = null;
     HostEntity hostEntity = null;
 
@@ -756,7 +763,7 @@ public class ClustersImpl implements Clusters {
   }
 
   @Transactional
-  private void unmapHostClusterEntities(String hostName, long clusterId) {
+  void unmapHostClusterEntities(String hostName, long clusterId) {
     HostEntity hostEntity = hostDAO.findByName(hostName);
     ClusterEntity clusterEntity = clusterDAO.findById(clusterId);
 
@@ -768,7 +775,7 @@ public class ClustersImpl implements Clusters {
   }
 
   @Transactional
-  private void deleteConfigGroupHostMapping(Long hostId) throws AmbariException {
+  void deleteConfigGroupHostMapping(Long hostId) throws AmbariException {
     // Remove Config group mapping
     for (Cluster cluster : clusters.values()) {
       for (ConfigGroup configGroup : cluster.getConfigGroups().values()) {
@@ -813,7 +820,7 @@ public class ClustersImpl implements Clusters {
    * @throws AmbariException
    */
   @Transactional
-  private void deleteHostEntityRelationships(String hostname) throws AmbariException {
+  void deleteHostEntityRelationships(String hostname) throws AmbariException {
     checkLoaded();
 
     if (!hosts.containsKey(hostname)) {
@@ -836,6 +843,17 @@ public class ClustersImpl implements Clusters {
       hostDAO.refresh(entity);
 
       hostVersionDAO.removeByHostName(hostname);
+
+      // Remove blueprint tasks before hostRoleCommands
+      // TopologyLogicalTask owns the OneToOne relationship but Cascade is on HostRoleCommandEntity
+      if (entity.getHostRoleCommandEntities() != null) {
+        for (HostRoleCommandEntity hrcEntity : entity.getHostRoleCommandEntities()) {
+          if (hrcEntity.getTopologyLogicalTaskEntity() != null) {
+            topologyLogicalTaskDAO.remove(hrcEntity.getTopologyLogicalTaskEntity());
+            hrcEntity.setTopologyLogicalTaskEntity(null);
+          }
+        }
+      }
       entity.setHostRoleCommandEntities(null);
       hostRoleCommandDAO.removeByHostId(entity.getHostId());
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/805f530b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestResourceProviderTest.java
index 9b63358..22aa124 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestResourceProviderTest.java
@@ -478,10 +478,10 @@ public class RequestResourceProviderTest {
     replay(managementController, actionManager, requestMock, requestMock1, requestDAO, hrcDAO);
 
     ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
-        type,
-        PropertyHelper.getPropertyIds(type),
-        PropertyHelper.getKeyPropertyIds(type),
-        managementController);
+      type,
+      PropertyHelper.getPropertyIds(type),
+      PropertyHelper.getKeyPropertyIds(type),
+      managementController);
 
     Set<String> propertyIds = new HashSet<String>();
 
@@ -590,7 +590,7 @@ public class RequestResourceProviderTest {
     expect(requestDAO.findByPks(capture(requestIdsCapture), eq(true))).andReturn(Arrays.asList(requestMock1));
 
     // IN_PROGRESS and PENDING
-    expect(hrcDAO.findAggregateCounts(100L)).andReturn(new HashMap<Long, HostRoleCommandStatusSummaryDTO>(){{
+    expect(hrcDAO.findAggregateCounts(100L)).andReturn(new HashMap<Long, HostRoleCommandStatusSummaryDTO>() {{
       put(1L, HostRoleCommandStatusSummaryDTO.create().inProgress(1).pending(1));
     }}).once();
 
@@ -1067,18 +1067,18 @@ public class RequestResourceProviderTest {
             host_component);
     requestInfoProperties.put(RequestOperationLevel.OPERATION_CLUSTER_ID, c1);
     requestInfoProperties.put(RequestOperationLevel.OPERATION_SERVICE_ID,
-            service_id);
+      service_id);
     requestInfoProperties.put(RequestOperationLevel.OPERATION_HOSTCOMPONENT_ID,
-            hostcomponent_id);
+      hostcomponent_id);
     requestInfoProperties.put(RequestOperationLevel.OPERATION_HOST_NAME,
-        host_name);
+      host_name);
 
     Request request = PropertyHelper.getCreateRequest(propertySet, requestInfoProperties);
     ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
-            type,
-            PropertyHelper.getPropertyIds(type),
-            PropertyHelper.getKeyPropertyIds(type),
-            managementController);
+      type,
+      PropertyHelper.getPropertyIds(type),
+      PropertyHelper.getKeyPropertyIds(type),
+      managementController);
 
     requestInfoProperties.put(RequestOperationLevel.OPERATION_CLUSTER_ID, c1);
 
@@ -1208,4 +1208,58 @@ public class RequestResourceProviderTest {
     verify(managementController, actionManager, clusters, requestMock, requestDAO, hrcDAO);
   }
 
+  @Test
+  public void testRequestStatusWithNoTasks() throws Exception {
+    Resource.Type type = Resource.Type.Request;
+
+    AmbariManagementController managementController = createMock(AmbariManagementController.class);
+    ActionManager actionManager = createNiceMock(ActionManager.class);
+
+    Clusters clusters = createNiceMock(Clusters.class);
+
+    RequestEntity requestMock = createNiceMock(RequestEntity.class);
+    expect(requestMock.getRequestContext()).andReturn("this is a context").anyTimes();
+    expect(requestMock.getRequestId()).andReturn(100L).anyTimes();
+
+    Capture<Collection<Long>> requestIdsCapture = new Capture<Collection<Long>>();
+
+    // set expectations
+    expect(managementController.getActionManager()).andReturn(actionManager).anyTimes();
+    expect(managementController.getClusters()).andReturn(clusters).anyTimes();
+    expect(clusters.getCluster(anyObject(String.class))).andReturn(null).anyTimes();
+    expect(requestDAO.findByPks(capture(requestIdsCapture), eq(true))).andReturn(Collections.singletonList(requestMock));
+    expect(hrcDAO.findAggregateCounts((Long) anyObject())).andReturn(
+      Collections.<Long, HostRoleCommandStatusSummaryDTO>emptyMap()).anyTimes();
+
+    // replay
+    replay(managementController, actionManager, clusters, requestMock, requestDAO, hrcDAO);
+
+    ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
+      type,
+      PropertyHelper.getPropertyIds(type),
+      PropertyHelper.getKeyPropertyIds(type),
+      managementController);
+
+    Set<String> propertyIds = new HashSet<String>();
+
+    propertyIds.add(RequestResourceProvider.REQUEST_ID_PROPERTY_ID);
+    propertyIds.add(RequestResourceProvider.REQUEST_STATUS_PROPERTY_ID);
+    propertyIds.add(RequestResourceProvider.REQUEST_PROGRESS_PERCENT_ID);
+
+    Predicate predicate = new PredicateBuilder().
+      property(RequestResourceProvider.REQUEST_ID_PROPERTY_ID).equals("100").
+      toPredicate();
+    Request request = PropertyHelper.getReadRequest(propertyIds);
+    Set<Resource> resources = provider.getResources(request, predicate);
+
+    Assert.assertEquals(1, resources.size());
+    for (Resource resource : resources) {
+      Assert.assertEquals(100L, (long) (Long) resource.getPropertyValue(RequestResourceProvider.REQUEST_ID_PROPERTY_ID));
+      Assert.assertEquals("COMPLETED", resource.getPropertyValue(RequestResourceProvider.REQUEST_STATUS_PROPERTY_ID));
+      Assert.assertEquals(100.0, resource.getPropertyValue(RequestResourceProvider.REQUEST_PROGRESS_PERCENT_ID));
+    }
+
+    // verify
+    verify(managementController, actionManager, clusters, requestMock, requestDAO, hrcDAO);
+  }
 }