Ver código fonte

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

Nate Cole 9 anos atrás
pai
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();
     Resource.Type resourceType    = getResourceDefinition().getType();
     Predicate     queryPredicate  = createPredicate(getKeyValueMap(), processUserPredicate(userPredicate));
     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
     // must occur after processing user predicate and prior to creating request
     finalizeProperties();
     finalizeProperties();
 
 
@@ -408,16 +413,16 @@ public class QueryImpl implements Query, ResourceInstance {
     }
     }
 
 
     // Optimization:
     // 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
     //   (1) Get *all* top-level resources
     //   (2) Populate 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
     //   (4) Apply pagination and predicate on resources from above
     //
     //
     // Though this works, it is very inefficient when either:
     // Though this works, it is very inefficient when either:
     //   (a) Predicate does not apply to sub-resources
     //   (a) Predicate does not apply to sub-resources
     //   (b) Page request is present
     //   (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
     // 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
     // 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
    *          └── CResource2
    *                p3:2
    *                p3:2
-   * 
+   *
    * Given the following query ...
    * Given the following query ...
-   * 
+   *
    *     api/v1/a_resources?b_resources/p1>3&b_resources/p2=5&c_resources/p3=1
    *     api/v1/a_resources?b_resources/p1>3&b_resources/p2=5&c_resources/p3=1
-   * 
+   *
    * The caller should pass the following property ids ...
    * The caller should pass the following property ids ...
-   * 
+   *
    *     b_resources/p1
    *     b_resources/p1
    *     b_resources/p2
    *     b_resources/p2
    *     c_resources/p3
    *     c_resources/p3
-   * 
+   *
    * getJoinedResourceProperties should produce the following map of property sets
    * getJoinedResourceProperties should produce the following map of property sets
    * by making recursive calls on the sub-resources of each of this query's resources,
    * 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
    * joining the resulting property sets, and adding them to the map keyed by the
    * resource ...
    * resource ...
-   * 
+   *
    *  {
    *  {
    *    AResource1=[{b_resources/p1=1, b_resources/p2=5, c_resources/p3=1},
    *    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},
    *                {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 -------------------------------------------------
   // ----- ClusterController -------------------------------------------------
 
 
+  @Override
+  public Predicate getAmendedPredicate(Type type, Predicate predicate) {
+    ExtendedResourceProviderWrapper provider = ensureResourceProviderWrapper(type);
+    ensurePropertyProviders(type);
+
+    return provider.getAmendedPredicate(predicate);
+  }
+
   @Override
   @Override
   public QueryResponse getResources(Type type, Request request, Predicate predicate)
   public QueryResponse getResources(Type type, Request request, Predicate predicate)
       throws UnsupportedPropertyException, NoSuchResourceException,
       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 ----------------------------------------
     // ----- ExtendedResourceProvider ----------------------------------------
 
 
     @Override
     @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;
 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
  * Helper class for maintaining RepositoryVersionEntity along with
@@ -28,11 +29,11 @@ import java.util.List;
  */
  */
 public class CompatibleRepositoryVersion {
 public class CompatibleRepositoryVersion {
   private RepositoryVersionEntity repositoryVersionEntity;
   private RepositoryVersionEntity repositoryVersionEntity;
-  private List<String> supportedTypes;
+  private Set<UpgradeType> supportedTypes;
 
 
   public CompatibleRepositoryVersion(RepositoryVersionEntity repositoryVersionEntity) {
   public CompatibleRepositoryVersion(RepositoryVersionEntity repositoryVersionEntity) {
     this.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.
    * @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).
    * @return List of supported Upgrade Type(s).
    */
    */
-  public List<String> getSupportedTypes() {
+  public Set<UpgradeType> getSupportedTypes() {
     return supportedTypes;
     return supportedTypes;
   }
   }
 
 
@@ -59,4 +58,5 @@ public class CompatibleRepositoryVersion {
   public RepositoryVersionEntity getRepositoryVersionEntity() {
   public RepositoryVersionEntity getRepositoryVersionEntity() {
     return repositoryVersionEntity;
     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;
 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.StaticallyInject;
 import org.apache.ambari.server.api.resources.OperatingSystemResourceDefinition;
 import org.apache.ambari.server.api.resources.OperatingSystemResourceDefinition;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.AmbariManagementController;
 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.NoSuchParentResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
 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.Resource.Type;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
 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.dao.RepositoryVersionDAO;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.stack.UpgradePack;
 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 ---------------------------------------------
   // ----- 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_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);
   private static Set<String> pkPropertyIds = Collections.singleton(REPOSITORY_VERSION_ID_PROPERTY_ID);
 
 
   static Set<String> propertyIds = Sets.newHashSet(
   static Set<String> propertyIds = Sets.newHashSet(
+    REPOSITORY_STACK_VALUE,
     REPOSITORY_VERSION_ID_PROPERTY_ID,
     REPOSITORY_VERSION_ID_PROPERTY_ID,
     REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID,
     REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID,
     REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID,
     REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID,
@@ -89,9 +96,6 @@ public class CompatibleRepositoryVersionResourceProvider extends ReadOnlyResourc
   @Inject
   @Inject
   private static Provider<AmbariMetaInfo> s_ambariMetaInfo;
   private static Provider<AmbariMetaInfo> s_ambariMetaInfo;
 
 
-  @Inject
-  private static Provider<RepositoryVersionHelper> s_repositoryVersionHelper;
-
   /**
   /**
    * Create a new resource provider.
    * Create a new resource provider.
    */
    */
@@ -106,76 +110,85 @@ public class CompatibleRepositoryVersionResourceProvider extends ReadOnlyResourc
     final Set<String> requestedIds = getRequestPropertyIds(request, predicate);
     final Set<String> requestedIds = getRequestPropertyIds(request, predicate);
     final Set<Map<String, Object>> propertyMaps = getPropertyMaps(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) {
     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()) {
             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 {
       } 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();
       RepositoryVersionEntity repositoryVersionEntity = entity.getRepositoryVersionEntity();
       final Resource resource = new ResourceImpl(Resource.Type.CompatibleRepositoryVersion);
       final Resource resource = new ResourceImpl(Resource.Type.CompatibleRepositoryVersion);
       setResourceProperty(resource, REPOSITORY_VERSION_ID_PROPERTY_ID, repositoryVersionEntity.getId(), requestedIds);
       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_NAME_PROPERTY_ID, repositoryVersionEntity.getStackName(), requestedIds);
       setResourceProperty(resource, REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID, repositoryVersionEntity.getStackVersion(), 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_DISPLAY_NAME_PROPERTY_ID, repositoryVersionEntity.getDisplayName(), requestedIds);
       setResourceProperty(resource, REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID, repositoryVersionEntity.getVersion(), requestedIds);
       setResourceProperty(resource, REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID, repositoryVersionEntity.getVersion(), requestedIds);
       setResourceProperty(resource, REPOSITORY_UPGRADES_SUPPORTED_TYPES_ID, entity.getSupportedTypes(), requestedIds);
       setResourceProperty(resource, REPOSITORY_UPGRADES_SUPPORTED_TYPES_ID, entity.getSupportedTypes(), requestedIds);
@@ -202,4 +215,89 @@ public class CompatibleRepositoryVersionResourceProvider extends ReadOnlyResourc
     return null;
     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 {
       NoSuchResourceException, NoSuchParentResourceException {
     throw new SystemException(READ_ONLY_MSG, null);
     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 java.util.Set;
 
 
+import org.apache.ambari.server.controller.spi.Resource.Type;
+
 /**
 /**
  * The cluster controller is the main access point for accessing resources
  * The cluster controller is the main access point for accessing resources
  * from the backend sources.  A cluster controller maintains a mapping of
  * 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
    * @param type the resource type
    * @return the schema object for the given resource
    * @return the schema object for the given resource
    */
    */
+  @Override
   public Schema getSchema(Resource.Type type);
   public Schema getSchema(Resource.Type type);
 
 
   /**
   /**
@@ -207,4 +210,12 @@ public interface ClusterController extends SchemaFactory {
              SystemException,
              SystemException,
              NoSuchResourceException,
              NoSuchResourceException,
              NoSuchParentResourceException ;
              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 {
   public void testExecute__Host_collection_AlertsSummary() throws Exception {
     ResourceDefinition resourceDefinition = new HostResourceDefinition();
     ResourceDefinition resourceDefinition = new HostResourceDefinition();
     Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
     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()) {
     ClusterControllerImpl clusterControllerImpl = new ClusterControllerImpl(new ClusterControllerImplTest.TestProviderModule()) {
+      @Override
       public PageResponse getPage(Resource.Type type, QueryResponse queryResponse, Request request, Predicate predicate, PageRequest pageRequest,
       public PageResponse getPage(Resource.Type type, QueryResponse queryResponse, Request request, Predicate predicate, PageRequest pageRequest,
           SortRequest sortRequest) throws UnsupportedPropertyException, SystemException, NoSuchResourceException, NoSuchParentResourceException {
           SortRequest sortRequest) throws UnsupportedPropertyException, SystemException, NoSuchResourceException, NoSuchParentResourceException {
         pageCallCount.incrementAndGet();
         pageCallCount.incrementAndGet();
@@ -666,7 +667,7 @@ public class QueryImplTest {
     TreeNode<Resource> tree = result.getResultTree();
     TreeNode<Resource> tree = result.getResultTree();
     Assert.assertEquals(4, tree.getChildren().size());
     Assert.assertEquals(4, tree.getChildren().size());
     Assert.assertEquals(1, pageCallCount.get());
     Assert.assertEquals(1, pageCallCount.get());
-    
+
     //test 2: Predicate = (alerts_summary/CRITICAL > 0)
     //test 2: Predicate = (alerts_summary/CRITICAL > 0)
     pageCallCount.set(0);
     pageCallCount.set(0);
     PredicateBuilder pb = new PredicateBuilder();
     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("host:2", hostNode.getObject().getPropertyValue(PropertyHelper.getPropertyId("Hosts", "host_name")));
     Assert.assertEquals(Resource.Type.Host, hostNode.getObject().getType());
     Assert.assertEquals(Resource.Type.Host, hostNode.getObject().getType());
     Assert.assertEquals("1", hostNode.getObject().getPropertyValue(PropertyHelper.getPropertyId("alerts_summary", "CRITICAL")));
     Assert.assertEquals("1", hostNode.getObject().getPropertyValue(PropertyHelper.getPropertyId("alerts_summary", "CRITICAL")));
-    
+
     // test 3: Predicate = (alerts_summary/WARNING > 0) AND Page = (size=1)
     // test 3: Predicate = (alerts_summary/WARNING > 0) AND Page = (size=1)
     pageCallCount.set(0);
     pageCallCount.set(0);
     pb = new PredicateBuilder();
     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.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.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.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(mockQueryResponse.getResources()).andReturn(Collections.singleton(mockResource)).atLeastOnce();
     expect(mockSubQueryResponse.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(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 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.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(mockQueryResponse.getResources()).andReturn(Collections.singleton(mockResource)).atLeastOnce();
     expect(mockSubQueryResponse.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.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.controller.ResourceProviderFactory;
 import org.apache.ambari.server.controller.ResourceProviderFactory;
 import org.apache.ambari.server.controller.predicate.AndPredicate;
 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.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.Resource;
 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", "1.1")).andReturn(stack1).atLeastOnce();
     expect(ambariMetaInfo.getStack("HDP", "2.2")).andReturn(stack2).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);
     replay(ambariMetaInfo);
 
 
@@ -272,9 +273,51 @@ public class CompatibleRepositoryVersionResourceProviderTest {
     assertEquals(2, resources.size());
     assertEquals(2, resources.size());
 
 
     // Test For Upgrade Types
     // 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));
     assertEquals(versionToUpgradeTypesMap.size(), checkUpgradeTypes(resources, versionToUpgradeTypesMap));
   }
   }
 
 
@@ -285,7 +328,7 @@ public class CompatibleRepositoryVersionResourceProviderTest {
    * @param versionToUpgradeTypesMap Contains 'Stack version' to 'Upgrade Type' Map.
    * @param versionToUpgradeTypesMap Contains 'Stack version' to 'Upgrade Type' Map.
    * @return count, 0 or number of Stack version's Upgrade Type(s) correctly compared.
    * @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;
     int count = 0;
     Iterator<Resource> itr = resources.iterator();
     Iterator<Resource> itr = resources.iterator();
     while (itr.hasNext()) {
     while (itr.hasNext()) {
@@ -295,9 +338,12 @@ public class CompatibleRepositoryVersionResourceProviderTest {
         Map<String, Object> propMap = resPropMap.get(resource);
         Map<String, Object> propMap = resPropMap.get(resource);
         String stackVersion = propMap.get("stack_version").toString();
         String stackVersion = propMap.get("stack_version").toString();
         if (versionToUpgradeTypesMap.containsKey(stackVersion)) {
         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);
           Collections.sort(upgradeTypes);
-          assertEquals(versionToUpgradeTypesMap.get(stackVersion), upgradeTypes);
+          Collections.sort(expectedTypes);
+
+          assertEquals(expectedTypes, upgradeTypes);
           count++;
           count++;
         }
         }
       }
       }