Browse Source

AMBARI-15717. Compatible Stacks not returning correctly (ncole)

Nate Cole 9 years ago
parent
commit
3e57dc24c7

+ 14 - 9
ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java

@@ -367,6 +367,11 @@ public class QueryImpl implements Query, ResourceInstance {
     Resource.Type resourceType    = getResourceDefinition().getType();
     Predicate     queryPredicate  = createPredicate(getKeyValueMap(), processUserPredicate(userPredicate));
 
+    Predicate updated = clusterController.getAmendedPredicate(resourceType, queryPredicate);
+    if (null != updated) {
+      queryPredicate = updated;
+    }
+
     // must occur after processing user predicate and prior to creating request
     finalizeProperties();
 
@@ -408,16 +413,16 @@ public class QueryImpl implements Query, ResourceInstance {
     }
 
     // Optimization:
-    // Currently the steps executed when sub-resources are requested are: 
+    // Currently the steps executed when sub-resources are requested are:
     //   (1) Get *all* top-level resources
     //   (2) Populate all top-level resources
-    //   (3) Query for and populate sub-resources of *all* top-level resources 
+    //   (3) Query for and populate sub-resources of *all* top-level resources
     //   (4) Apply pagination and predicate on resources from above
     //
     // Though this works, it is very inefficient when either:
     //   (a) Predicate does not apply to sub-resources
     //   (b) Page request is present
-    // It is inefficient because we needlessly populate sub-resources that might not get 
+    // It is inefficient because we needlessly populate sub-resources that might not get
     // used due to their top-level resources being filtered out by the predicate and paging
     //
     // The optimization is to apply the predicate and paging request on the top-level resources
@@ -551,22 +556,22 @@ public class QueryImpl implements Query, ResourceInstance {
    *          │
    *          └── CResource2
    *                p3:2
-   * 
+   *
    * Given the following query ...
-   * 
+   *
    *     api/v1/a_resources?b_resources/p1>3&b_resources/p2=5&c_resources/p3=1
-   * 
+   *
    * The caller should pass the following property ids ...
-   * 
+   *
    *     b_resources/p1
    *     b_resources/p2
    *     c_resources/p3
-   * 
+   *
    * getJoinedResourceProperties should produce the following map of property sets
    * by making recursive calls on the sub-resources of each of this query's resources,
    * joining the resulting property sets, and adding them to the map keyed by the
    * resource ...
-   * 
+   *
    *  {
    *    AResource1=[{b_resources/p1=1, b_resources/p2=5, c_resources/p3=1},
    *                {b_resources/p1=2, b_resources/p2=0, c_resources/p3=1},

+ 21 - 0
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterControllerImpl.java

@@ -108,8 +108,17 @@ public class ClusterControllerImpl implements ClusterController {
   }
 
 
+
   // ----- ClusterController -------------------------------------------------
 
+  @Override
+  public Predicate getAmendedPredicate(Type type, Predicate predicate) {
+    ExtendedResourceProviderWrapper provider = ensureResourceProviderWrapper(type);
+    ensurePropertyProviders(type);
+
+    return provider.getAmendedPredicate(predicate);
+  }
+
   @Override
   public QueryResponse getResources(Type type, Request request, Predicate predicate)
       throws UnsupportedPropertyException, NoSuchResourceException,
@@ -937,6 +946,18 @@ public class ClusterControllerImpl implements ClusterController {
     }
 
 
+    /**
+     * @return the amended predicate, or {@code null} to use the provided one
+     */
+    public Predicate getAmendedPredicate(Predicate predicate) {
+      if (ReadOnlyResourceProvider.class.isInstance(resourceProvider)) {
+        return ((ReadOnlyResourceProvider) resourceProvider).amendPredicate(predicate);
+      } else {
+        return null;
+      }
+    }
+
+
     // ----- ExtendedResourceProvider ----------------------------------------
 
     @Override

+ 10 - 10
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/CompatibleRepositoryVersion.java

@@ -17,10 +17,11 @@
  */
 package org.apache.ambari.server.controller.internal;
 
-import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
+import java.util.HashSet;
+import java.util.Set;
 
-import java.util.ArrayList;
-import java.util.List;
+import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
+import org.apache.ambari.server.state.stack.upgrade.UpgradeType;
 
 /**
  * Helper class for maintaining RepositoryVersionEntity along with
@@ -28,11 +29,11 @@ import java.util.List;
  */
 public class CompatibleRepositoryVersion {
   private RepositoryVersionEntity repositoryVersionEntity;
-  private List<String> supportedTypes;
+  private Set<UpgradeType> supportedTypes;
 
   public CompatibleRepositoryVersion(RepositoryVersionEntity repositoryVersionEntity) {
     this.repositoryVersionEntity = repositoryVersionEntity;
-    this.supportedTypes = new ArrayList<String>();
+    this.supportedTypes = new HashSet<>();
   }
 
   /**
@@ -40,16 +41,14 @@ public class CompatibleRepositoryVersion {
    *
    * @param type Supported Upgrade Type.
    */
-  public void addUpgradePackType(String type) {
-    if (!supportedTypes.contains(type)) {
-      supportedTypes.add(type);
-    }
+  public void addUpgradePackType(UpgradeType type) {
+    supportedTypes.add(type);
   }
 
   /**
    * @return List of supported Upgrade Type(s).
    */
-  public List<String> getSupportedTypes() {
+  public Set<UpgradeType> getSupportedTypes() {
     return supportedTypes;
   }
 
@@ -59,4 +58,5 @@ public class CompatibleRepositoryVersion {
   public RepositoryVersionEntity getRepositoryVersionEntity() {
     return repositoryVersionEntity;
   }
+
 }

+ 170 - 72
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/CompatibleRepositoryVersionResourceProvider.java

@@ -17,13 +17,22 @@
  */
 package org.apache.ambari.server.controller.internal;
 
-import com.google.common.collect.Sets;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
 import org.apache.ambari.server.StaticallyInject;
 import org.apache.ambari.server.api.resources.OperatingSystemResourceDefinition;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.AmbariManagementController;
+import org.apache.ambari.server.controller.predicate.AndPredicate;
+import org.apache.ambari.server.controller.predicate.EqualsPredicate;
+import org.apache.ambari.server.controller.predicate.OrPredicate;
 import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
@@ -32,19 +41,15 @@ import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.Resource.Type;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.stack.UpgradePack;
-import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
 
 
 /**
@@ -55,17 +60,19 @@ public class CompatibleRepositoryVersionResourceProvider extends ReadOnlyResourc
 
   // ----- Property ID constants ---------------------------------------------
 
-  public static final String REPOSITORY_VERSION_ID_PROPERTY_ID = "CompatibleRepositoryVersions/id";
-  public static final String REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID = "CompatibleRepositoryVersions/stack_name";
-  public static final String REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID = "CompatibleRepositoryVersions/stack_version";
+  public static final String REPOSITORY_VERSION_ID_PROPERTY_ID                 = "CompatibleRepositoryVersions/id";
+  public static final String REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID         = "CompatibleRepositoryVersions/stack_name";
+  public static final String REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID      = "CompatibleRepositoryVersions/stack_version";
   public static final String REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID = "CompatibleRepositoryVersions/repository_version";
-  public static final String REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID = "CompatibleRepositoryVersions/display_name";
-  public static final String REPOSITORY_UPGRADES_SUPPORTED_TYPES_ID = "CompatibleRepositoryVersions/upgrade_types";
-  public static final String SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID = new OperatingSystemResourceDefinition().getPluralName();
+  public static final String REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID       = "CompatibleRepositoryVersions/display_name";
+  public static final String REPOSITORY_UPGRADES_SUPPORTED_TYPES_ID            = "CompatibleRepositoryVersions/upgrade_types";
+  public static final String SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID         = new OperatingSystemResourceDefinition().getPluralName();
+  private static final String REPOSITORY_STACK_VALUE                           = "stack_value";
 
   private static Set<String> pkPropertyIds = Collections.singleton(REPOSITORY_VERSION_ID_PROPERTY_ID);
 
   static Set<String> propertyIds = Sets.newHashSet(
+    REPOSITORY_STACK_VALUE,
     REPOSITORY_VERSION_ID_PROPERTY_ID,
     REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID,
     REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID,
@@ -89,9 +96,6 @@ public class CompatibleRepositoryVersionResourceProvider extends ReadOnlyResourc
   @Inject
   private static Provider<AmbariMetaInfo> s_ambariMetaInfo;
 
-  @Inject
-  private static Provider<RepositoryVersionHelper> s_repositoryVersionHelper;
-
   /**
    * Create a new resource provider.
    */
@@ -106,76 +110,85 @@ public class CompatibleRepositoryVersionResourceProvider extends ReadOnlyResourc
     final Set<String> requestedIds = getRequestPropertyIds(request, predicate);
     final Set<Map<String, Object>> propertyMaps = getPropertyMaps(predicate);
 
-    List<CompatibleRepositoryVersion> requestedEntities = new ArrayList<CompatibleRepositoryVersion>();
-    String currentStackUniqueId = null;
-    Map<String, CompatibleRepositoryVersion> compatibleRepositoryVersionsMap = new HashMap<String, CompatibleRepositoryVersion>();
+    Long currentStackUniqueId = null;
+    Map<Long, CompatibleRepositoryVersion> compatibleRepositoryVersionsMap = new HashMap<>();
 
+    StackId stackId = null;
+    // !!! this is the case where the predicate was altered to include all stacks
     for (Map<String, Object> propertyMap : propertyMaps) {
+      if (propertyMap.containsKey(REPOSITORY_STACK_VALUE)) {
+        stackId = new StackId(propertyMap.get(REPOSITORY_STACK_VALUE).toString());
+        break;
+      }
+    }
 
-      final StackId stackId = getStackInformationFromUrl(propertyMap);
+    if (null == stackId) {
+      if (propertyMaps.size() == 1) {
+        Map<String, Object> propertyMap = propertyMaps.iterator().next();
+        stackId = getStackInformationFromUrl(propertyMap);
+      } else {
+        LOG.error("Property Maps size is NOT equal to 1. Current 'propertyMaps' size = {}", propertyMaps.size());
+      }
+    }
 
-      if (stackId != null) {
-        if (propertyMaps.size() == 1) {
-          if (LOG.isDebugEnabled()) {
-            LOG.debug("Stack Name : " + stackId.getStackName() + ", Stack Version : " + stackId.getStackVersion());
-          }
-          for (RepositoryVersionEntity repositoryVersionEntity : s_repositoryVersionDAO.findByStack(stackId)) {
-            currentStackUniqueId = Long.toString(repositoryVersionEntity.getId());
-            compatibleRepositoryVersionsMap.put(currentStackUniqueId, new CompatibleRepositoryVersion(repositoryVersionEntity));
+    if (null == stackId) {
+      LOG.error("Could not determine stack to process.  Returning empty set.");
+      return resources;
+    }
+
+    for (RepositoryVersionEntity repositoryVersionEntity : s_repositoryVersionDAO.findByStack(stackId)) {
+      currentStackUniqueId = repositoryVersionEntity.getId();
+      compatibleRepositoryVersionsMap.put(repositoryVersionEntity.getId(),
+          new CompatibleRepositoryVersion(repositoryVersionEntity));
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Added current stack id: {} to map", repositoryVersionEntity.getId());
+      }
+    }
+
+    Map<String, UpgradePack> packs = s_ambariMetaInfo.get().getUpgradePacks(
+      stackId.getStackName(), stackId.getStackVersion());
+
+    for (UpgradePack up : packs.values()) {
+      if (null != up.getTargetStack()) {
+        StackId targetStackId = new StackId(up.getTargetStack());
+        List<RepositoryVersionEntity> repositoryVersionEntities = s_repositoryVersionDAO.findByStack(targetStackId);
+
+        for (RepositoryVersionEntity repositoryVersionEntity : repositoryVersionEntities) {
+          if (compatibleRepositoryVersionsMap.containsKey(repositoryVersionEntity.getId())) {
+            compatibleRepositoryVersionsMap.get(repositoryVersionEntity.getId()).addUpgradePackType(up.getType());
             if (LOG.isDebugEnabled()) {
-              LOG.debug("Added current stack id : " + currentStackUniqueId + " to Map.");
+              LOG.debug("Stack id: {} exists in map.  Appended new upgrade type {}" + repositoryVersionEntity.getId(), up.getType());
             }
-          }
-
-          Map<String, UpgradePack> packs = s_ambariMetaInfo.get().getUpgradePacks(
-            stackId.getStackName(), stackId.getStackVersion());
-
-          for (UpgradePack up : packs.values()) {
-            if (null != up.getTargetStack()) {
-              StackId targetStackId = new StackId(up.getTargetStack());
-              List<RepositoryVersionEntity> repositoryVersionEntities = s_repositoryVersionDAO.findByStack(targetStackId);
-              for (RepositoryVersionEntity repositoryVersionEntity : repositoryVersionEntities) {
-                if (compatibleRepositoryVersionsMap.containsKey(Long.toString(repositoryVersionEntity.getId()))) {
-                  compatibleRepositoryVersionsMap.get(Long.toString(repositoryVersionEntity.getId())).addUpgradePackType(up.getType().toString());
-                  if (LOG.isDebugEnabled()) {
-                    LOG.debug("Stack id : " + repositoryVersionEntity.getId() + " exists in Map. " + "Appended new Upgrade type : " + up.getType());
-                  }
-                } else {
-                  CompatibleRepositoryVersion compatibleRepositoryVersionEntity = new CompatibleRepositoryVersion(repositoryVersionEntity);
-                  compatibleRepositoryVersionEntity.addUpgradePackType(up.getType().toString());
-                  compatibleRepositoryVersionsMap.put(Long.toString(repositoryVersionEntity.getId()), compatibleRepositoryVersionEntity);
-                  if (LOG.isDebugEnabled()) {
-                    LOG.debug("Added Stack id : " + repositoryVersionEntity.getId() + " to Map with Upgrade type : " + up.getType());
-                  }
-                }
-              }
-            } else {
-              if (currentStackUniqueId != null) {
-                compatibleRepositoryVersionsMap.get(currentStackUniqueId).addUpgradePackType(up.getType().toString());
-                if (LOG.isDebugEnabled()) {
-                  LOG.debug("Current Stack id : " + currentStackUniqueId + " retrieved from Map. Added Upgrade type : " + up.getType());
-                }
-              } else {
-                LOG.error("Couldn't retrieve Current stack entry from Map.");
-              }
+          } else {
+            CompatibleRepositoryVersion compatibleRepositoryVersionEntity = new CompatibleRepositoryVersion(repositoryVersionEntity);
+            compatibleRepositoryVersionEntity.addUpgradePackType(up.getType());
+            compatibleRepositoryVersionsMap.put(repositoryVersionEntity.getId(), compatibleRepositoryVersionEntity);
+            if (LOG.isDebugEnabled()) {
+              LOG.debug("Added Stack id: {} to map with upgrade type {}", repositoryVersionEntity.getId(), up.getType());
             }
           }
-
-        } else {
-          LOG.error("Property Maps size NOT equal to 1. Current 'propertyMaps' size = " + propertyMaps.size());
         }
       } else {
-        LOG.error("StackId is NULL.");
+        if (currentStackUniqueId != null) {
+          compatibleRepositoryVersionsMap.get(currentStackUniqueId).addUpgradePackType(up.getType());
+          if (LOG.isDebugEnabled()) {
+            LOG.debug("Current Stack id: {} retrieved from map. Added upgrade type {}", currentStackUniqueId, up.getType());
+          }
+        } else {
+          LOG.error("Couldn't retrieve Current stack entry from Map.");
+        }
       }
     }
 
-    for (String stackId : compatibleRepositoryVersionsMap.keySet()) {
-      CompatibleRepositoryVersion entity = compatibleRepositoryVersionsMap.get(stackId);
+    for (CompatibleRepositoryVersion entity : compatibleRepositoryVersionsMap.values()) {
+
       RepositoryVersionEntity repositoryVersionEntity = entity.getRepositoryVersionEntity();
       final Resource resource = new ResourceImpl(Resource.Type.CompatibleRepositoryVersion);
       setResourceProperty(resource, REPOSITORY_VERSION_ID_PROPERTY_ID, repositoryVersionEntity.getId(), requestedIds);
+
       setResourceProperty(resource, REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID, repositoryVersionEntity.getStackName(), requestedIds);
       setResourceProperty(resource, REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID, repositoryVersionEntity.getStackVersion(), requestedIds);
+
       setResourceProperty(resource, REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID, repositoryVersionEntity.getDisplayName(), requestedIds);
       setResourceProperty(resource, REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID, repositoryVersionEntity.getVersion(), requestedIds);
       setResourceProperty(resource, REPOSITORY_UPGRADES_SUPPORTED_TYPES_ID, entity.getSupportedTypes(), requestedIds);
@@ -202,4 +215,89 @@ public class CompatibleRepositoryVersionResourceProvider extends ReadOnlyResourc
     return null;
   }
 
+  /**
+   * Identify the case where this is a top-level request, containing ONLY the stack name
+   * and stack version. Determine all other compatible stacks and make a new Predicate
+   * out of them.
+   *
+   * Consider a stack STACK-2.2 that is compatible with 2.3 and 2.4.  The result of this
+   * call will be a predicate like so (abbreviated):
+   * <pre>
+   * in -> AndPredicate([stack_name=STACK],[stack_version=2.2])
+   * out-> OrPredicate(
+   *         AndPredicate([stack_name=STACK],[stack_version=2.2]),
+   *         AndPredicate([stack_name=STACK],[stack_version=2.3]),
+   *         AndPredicate([stack_name=STACK],[stack_version=2.4]) )
+   * </pre>
+   *
+   * Any input predicate that does not conform to ONLY stack_name/stack_version will
+   * revert to the that predicate (return {@code null}).
+   */
+  @SuppressWarnings("rawtypes")
+  @Override
+  public Predicate amendPredicate(Predicate predicate) {
+    if (!AndPredicate.class.isInstance(predicate)) {
+      return null;
+    }
+
+    AndPredicate ap = (AndPredicate) predicate;
+    if (2 != ap.getPropertyIds().size()) {
+      return null;
+    }
+
+    if (!ap.getPropertyIds().contains(REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID) &&
+        !ap.getPropertyIds().contains(REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID)) {
+      return null;
+    }
+
+    Predicate[] predicates = ap.getPredicates();
+    if (!EqualsPredicate.class.isInstance(predicates[0]) || !EqualsPredicate.class.isInstance(predicates[1])) {
+      return null;
+    }
+
+    EqualsPredicate pred1 = (EqualsPredicate) predicates[0];
+    EqualsPredicate pred2 = (EqualsPredicate) predicates[1];
+
+    StackId stackId = null;
+    if (pred1.getPropertyId().equals(REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID)) {
+      stackId = new StackId(pred1.getValue().toString(), pred2.getValue().toString());
+    } else {
+      stackId = new StackId(pred2.getValue().toString(), pred1.getValue().toString());
+    }
+
+    Map<String, UpgradePack> packs = s_ambariMetaInfo.get().getUpgradePacks(
+        stackId.getStackName(), stackId.getStackVersion());
+
+    Set<String> stackIds = new HashSet<>();
+
+    for (Entry<String, UpgradePack> entry : packs.entrySet()) {
+      UpgradePack pack = entry.getValue();
+      String packStack = pack.getTargetStack();
+      if (null == packStack || !packStack.equals(stackId.toString())) {
+        stackIds.add(packStack);
+      }
+    }
+
+
+    // !!! use the one passed in, it already includes the one of interest
+    List<Predicate> usable = new ArrayList<>();
+    usable.add(predicate);
+
+    // !!! add predicate for each of the compatible stacks as found by the upgrade packs
+    for (String requiredStack : stackIds) {
+      StackId targetStack = new StackId(requiredStack);
+      Predicate p = new PredicateBuilder().property(REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID).equals(targetStack.getStackName())
+          .and().property(REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID).equals(targetStack.getStackVersion()).toPredicate();
+      usable.add(p);
+    }
+
+    // !!! add the stack that is used to find compatible versions for
+    Predicate p = new PredicateBuilder().property(REPOSITORY_STACK_VALUE).equals(stackId.toString()).toPredicate();
+    usable.add(p);
+
+    p = new OrPredicate(usable.toArray(new Predicate[usable.size()]));
+
+    return p;
+  }
+
 }

+ 12 - 0
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ReadOnlyResourceProvider.java

@@ -70,4 +70,16 @@ public abstract class ReadOnlyResourceProvider extends AbstractControllerResourc
       NoSuchResourceException, NoSuchParentResourceException {
     throw new SystemException(READ_ONLY_MSG, null);
   }
+
+  /**
+   * Get an amended predicate used when use {@link #getResources(Request, Predicate)}.  This
+   * is needed in cases where the resource might incorrectly be filtered during predicate processing.
+   * Changing the predicate allows them to be included.
+   * @param predicate the predicate passed in the request
+   * @return the new predicate, or {@code null} to leave the predicate unchanged.
+   */
+  public Predicate amendPredicate(Predicate predicate) {
+    // TODO Auto-generated method stub
+    return null;
+  }
 }

+ 11 - 0
ambari-server/src/main/java/org/apache/ambari/server/controller/spi/ClusterController.java

@@ -19,6 +19,8 @@ package org.apache.ambari.server.controller.spi;
 
 import java.util.Set;
 
+import org.apache.ambari.server.controller.spi.Resource.Type;
+
 /**
  * The cluster controller is the main access point for accessing resources
  * from the backend sources.  A cluster controller maintains a mapping of
@@ -132,6 +134,7 @@ public interface ClusterController extends SchemaFactory {
    * @param type the resource type
    * @return the schema object for the given resource
    */
+  @Override
   public Schema getSchema(Resource.Type type);
 
   /**
@@ -207,4 +210,12 @@ public interface ClusterController extends SchemaFactory {
              SystemException,
              NoSuchResourceException,
              NoSuchParentResourceException ;
+
+  /**
+   * Gets the amended predicate for a resource.
+   * @param type      the type of the resource
+   * @param predicate the predicate object to use for filtering
+   * @return the new predicate used for filtering
+   */
+  Predicate getAmendedPredicate(Type type, Predicate predicate);
 }

+ 6 - 3
ambari-server/src/test/java/org/apache/ambari/server/api/query/QueryImplTest.java

@@ -650,8 +650,9 @@ public class QueryImplTest {
   public void testExecute__Host_collection_AlertsSummary() throws Exception {
     ResourceDefinition resourceDefinition = new HostResourceDefinition();
     Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
-    final AtomicInteger pageCallCount = new AtomicInteger(0); 
+    final AtomicInteger pageCallCount = new AtomicInteger(0);
     ClusterControllerImpl clusterControllerImpl = new ClusterControllerImpl(new ClusterControllerImplTest.TestProviderModule()) {
+      @Override
       public PageResponse getPage(Resource.Type type, QueryResponse queryResponse, Request request, Predicate predicate, PageRequest pageRequest,
           SortRequest sortRequest) throws UnsupportedPropertyException, SystemException, NoSuchResourceException, NoSuchParentResourceException {
         pageCallCount.incrementAndGet();
@@ -666,7 +667,7 @@ public class QueryImplTest {
     TreeNode<Resource> tree = result.getResultTree();
     Assert.assertEquals(4, tree.getChildren().size());
     Assert.assertEquals(1, pageCallCount.get());
-    
+
     //test 2: Predicate = (alerts_summary/CRITICAL > 0)
     pageCallCount.set(0);
     PredicateBuilder pb = new PredicateBuilder();
@@ -686,7 +687,7 @@ public class QueryImplTest {
     Assert.assertEquals("host:2", hostNode.getObject().getPropertyValue(PropertyHelper.getPropertyId("Hosts", "host_name")));
     Assert.assertEquals(Resource.Type.Host, hostNode.getObject().getType());
     Assert.assertEquals("1", hostNode.getObject().getPropertyValue(PropertyHelper.getPropertyId("alerts_summary", "CRITICAL")));
-    
+
     // test 3: Predicate = (alerts_summary/WARNING > 0) AND Page = (size=1)
     pageCallCount.set(0);
     pb = new PredicateBuilder();
@@ -976,6 +977,7 @@ public class QueryImplTest {
     expect(mockClusterController.getResources(eq(Resource.Type.Configuration), isA(Request.class), (Predicate)eq(null))).andReturn(mockSubQueryResponse).atLeastOnce();
     expect(mockClusterController.getIterable(eq(Resource.Type.Host), isA(QueryResponse.class), isA(Request.class),(Predicate)eq(null), (PageRequest)eq(null), (SortRequest)eq(null))).andReturn(Collections.singleton(mockResource)).atLeastOnce();
     expect(mockClusterController.getIterable(eq(Resource.Type.Configuration), isA(QueryResponse.class), isA(Request.class),(Predicate)eq(null), (PageRequest)eq(null), (SortRequest)eq(null))).andReturn(Collections.singleton(mockResource)).atLeastOnce();
+    expect(mockClusterController.getAmendedPredicate(eq(Resource.Type.Host), (Predicate)eq(null))).andReturn((Predicate)null).atLeastOnce();
 
     expect(mockQueryResponse.getResources()).andReturn(Collections.singleton(mockResource)).atLeastOnce();
     expect(mockSubQueryResponse.getResources()).andReturn(Collections.singleton(mockResource)).atLeastOnce();
@@ -1056,6 +1058,7 @@ public class QueryImplTest {
     expect(mockClusterController.populateResources(eq(Resource.Type.Host), eq(Collections.singleton(mockResource)), isA(Request.class), (Predicate)eq(null))).andReturn(Collections.<Resource>emptySet()).times(1);
     // expect call to activate property providers for Configuration sub-resource
     expect(mockClusterController.populateResources(eq(Resource.Type.Configuration), eq(Collections.singleton(mockResource)), isA(Request.class), (Predicate)eq(null))).andReturn(Collections.<Resource>emptySet()).times(1);
+    expect(mockClusterController.getAmendedPredicate(eq(Resource.Type.Host), (Predicate)eq(null))).andReturn((Predicate)null).atLeastOnce();
 
     expect(mockQueryResponse.getResources()).andReturn(Collections.singleton(mockResource)).atLeastOnce();
     expect(mockSubQueryResponse.getResources()).andReturn(Collections.singleton(mockResource)).atLeastOnce();

+ 54 - 8
ambari-server/src/test/java/org/apache/ambari/server/controller/internal/CompatibleRepositoryVersionResourceProviderTest.java

@@ -34,6 +34,7 @@ import java.util.Set;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.ResourceProviderFactory;
 import org.apache.ambari.server.controller.predicate.AndPredicate;
+import org.apache.ambari.server.controller.predicate.OrPredicate;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.Resource;
@@ -224,8 +225,8 @@ public class CompatibleRepositoryVersionResourceProviderTest {
 
     expect(ambariMetaInfo.getStack("HDP", "1.1")).andReturn(stack1).atLeastOnce();
     expect(ambariMetaInfo.getStack("HDP", "2.2")).andReturn(stack2).atLeastOnce();
-    expect(ambariMetaInfo.getUpgradePacks("HDP", "1.1")).andReturn(stack1.getUpgradePacks());
-    expect(ambariMetaInfo.getUpgradePacks("HDP", "2.2")).andReturn(stack2.getUpgradePacks());
+    expect(ambariMetaInfo.getUpgradePacks("HDP", "1.1")).andReturn(stack1.getUpgradePacks()).atLeastOnce();
+    expect(ambariMetaInfo.getUpgradePacks("HDP", "2.2")).andReturn(stack2.getUpgradePacks()).atLeastOnce();
 
     replay(ambariMetaInfo);
 
@@ -272,9 +273,51 @@ public class CompatibleRepositoryVersionResourceProviderTest {
     assertEquals(2, resources.size());
 
     // Test For Upgrade Types
-    Map<String, List<String>> versionToUpgradeTypesMap = new HashMap<String, List<String>>();
-    versionToUpgradeTypesMap.put("1.1", Arrays.asList("ROLLING"));
-    versionToUpgradeTypesMap.put("2.2", Arrays.asList("NON_ROLLING", "ROLLING"));
+    Map<String, List<UpgradeType>> versionToUpgradeTypesMap = new HashMap<>();
+    versionToUpgradeTypesMap.put("1.1", Arrays.asList(UpgradeType.ROLLING));
+    versionToUpgradeTypesMap.put("2.2", Arrays.asList(UpgradeType.NON_ROLLING, UpgradeType.ROLLING));
+    assertEquals(versionToUpgradeTypesMap.size(), checkUpgradeTypes(resources, versionToUpgradeTypesMap));
+  }
+
+  @Test
+  public void testGetResourcesWithAmendedPredicate() throws Exception {
+    SecurityContextHolder.getContext().setAuthentication(TestAuthenticationFactory.createClusterAdministrator("admin", 2L));
+
+    final ResourceProvider provider = injector.getInstance(ResourceProviderFactory.class).getRepositoryVersionResourceProvider();
+
+    Request getRequest = PropertyHelper.getReadRequest(
+      RepositoryVersionResourceProvider.REPOSITORY_VERSION_ID_PROPERTY_ID,
+      RepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID,
+      RepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID,
+      CompatibleRepositoryVersionResourceProvider.REPOSITORY_UPGRADES_SUPPORTED_TYPES_ID);
+    Predicate predicateStackName = new PredicateBuilder().property(RepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID).equals("HDP").toPredicate();
+    Predicate predicateStackVersion = new PredicateBuilder().property(RepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID).equals("1.1").toPredicate();
+
+    // !!! non-compatible, within stack
+    assertEquals(1, provider.getResources(getRequest, new AndPredicate(predicateStackName, predicateStackVersion)).size());
+
+    CompatibleRepositoryVersionResourceProvider compatibleProvider = new CompatibleRepositoryVersionResourceProvider(null);
+
+    getRequest = PropertyHelper.getReadRequest(
+      CompatibleRepositoryVersionResourceProvider.REPOSITORY_VERSION_ID_PROPERTY_ID,
+      CompatibleRepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID,
+      CompatibleRepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID,
+      CompatibleRepositoryVersionResourceProvider.REPOSITORY_UPGRADES_SUPPORTED_TYPES_ID);
+    predicateStackName = new PredicateBuilder().property(CompatibleRepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID).equals("HDP").toPredicate();
+    predicateStackVersion = new PredicateBuilder().property(CompatibleRepositoryVersionResourceProvider.REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID).equals("1.1").toPredicate();
+
+    // !!! compatible, across stack
+    Predicate newPredicate = compatibleProvider.amendPredicate(new AndPredicate(predicateStackName, predicateStackVersion));
+
+    assertEquals(OrPredicate.class, newPredicate.getClass());
+
+    Set<Resource> resources = compatibleProvider.getResources(getRequest, newPredicate);
+    assertEquals(2, resources.size());
+
+    // Test For Upgrade Types
+    Map<String, List<UpgradeType>> versionToUpgradeTypesMap = new HashMap<>();
+    versionToUpgradeTypesMap.put("1.1", Arrays.asList(UpgradeType.ROLLING));
+    versionToUpgradeTypesMap.put("2.2", Arrays.asList(UpgradeType.NON_ROLLING, UpgradeType.ROLLING));
     assertEquals(versionToUpgradeTypesMap.size(), checkUpgradeTypes(resources, versionToUpgradeTypesMap));
   }
 
@@ -285,7 +328,7 @@ public class CompatibleRepositoryVersionResourceProviderTest {
    * @param versionToUpgradeTypesMap Contains 'Stack version' to 'Upgrade Type' Map.
    * @return count, 0 or number of Stack version's Upgrade Type(s) correctly compared.
    */
-  public int checkUpgradeTypes(Set<Resource> resources, Map<String, List<String>> versionToUpgradeTypesMap) {
+  public int checkUpgradeTypes(Set<Resource> resources, Map<String, List<UpgradeType>> versionToUpgradeTypesMap) {
     int count = 0;
     Iterator<Resource> itr = resources.iterator();
     while (itr.hasNext()) {
@@ -295,9 +338,12 @@ public class CompatibleRepositoryVersionResourceProviderTest {
         Map<String, Object> propMap = resPropMap.get(resource);
         String stackVersion = propMap.get("stack_version").toString();
         if (versionToUpgradeTypesMap.containsKey(stackVersion)) {
-          List<String> upgradeTypes = new ArrayList<>((List<String>)propMap.get("upgrade_types"));
+          List<UpgradeType> upgradeTypes = new ArrayList<>((Set<UpgradeType>)propMap.get("upgrade_types"));
+          List<UpgradeType> expectedTypes = versionToUpgradeTypesMap.get(stackVersion);
           Collections.sort(upgradeTypes);
-          assertEquals(versionToUpgradeTypesMap.get(stackVersion), upgradeTypes);
+          Collections.sort(expectedTypes);
+
+          assertEquals(expectedTypes, upgradeTypes);
           count++;
         }
       }