Repository: ambari
Updated Branches:
  refs/heads/branch-feature-AMBARI-14714 2f1f96ef5 -> 7e967d4f7


AMBARI-21655: Add Upgrade Mpack Recommendations (jluniya)


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

Branch: refs/heads/branch-feature-AMBARI-14714
Commit: 7e967d4f7da83808afd732d9df42477a5bf92540
Parents: 2f1f96e
Author: Jayush Luniya <[email protected]>
Authored: Thu Aug 3 15:05:28 2017 -0700
Committer: Jayush Luniya <[email protected]>
Committed: Thu Aug 3 15:05:28 2017 -0700

----------------------------------------------------------------------
 .../RegistryAdvisorResourceProvider.java        |  31 ++-
 .../RegistryRecommendationResourceProvider.java |  11 +-
 .../RegistryValidationResourceProvider.java     |  16 +-
 .../ambari/server/registry/MpackBundle.java     |  55 ++++
 .../ambari/server/registry/MpackEntry.java      |   4 +-
 .../ambari/server/registry/RegistryAdvisor.java | 262 +++++++++++++++++--
 .../server/registry/RegistryAdvisorRequest.java |  19 +-
 .../registry/RegistryAdvisorResponse.java       |   6 +-
 .../RegistryRecommendationResponse.java         |   9 +-
 .../registry/RegistryValidationResponse.java    |  20 +-
 .../ambari/server/registry/ScenarioEntry.java   |  60 +++++
 11 files changed, 436 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/7e967d4f/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryAdvisorResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryAdvisorResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryAdvisorResourceProvider.java
index 87d8102..9a6b791 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryAdvisorResourceProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryAdvisorResourceProvider.java
@@ -34,6 +34,7 @@ import org.apache.ambari.server.registry.RegistryAdvisor;
 import org.apache.ambari.server.registry.RegistryAdvisorRequest;
 import 
org.apache.ambari.server.registry.RegistryAdvisorRequest.RegistryAdvisorRequestBuilder;
 import 
org.apache.ambari.server.registry.RegistryAdvisorRequest.RegistryAdvisorRequestType;
+import org.apache.ambari.server.registry.ScenarioEntry;
 
 import com.google.inject.Inject;
 
@@ -42,7 +43,8 @@ import com.google.inject.Inject;
  */
 public abstract class RegistryAdvisorResourceProvider extends 
AbstractControllerResourceProvider {
 
-  public static final String REGISTRY_ID =  
PropertyHelper.getPropertyId("RegistryInfo", "registry_id");
+  public static final String REGISTRY_ID_PROPERTY_ID =  
PropertyHelper.getPropertyId("RegistryInfo", "registry_id");
+  protected static final String CLUSTER_NAME_PROPERTY_ID = "cluster_name";
   protected static final String SELECTED_SCENARIOS_PROPERTY_ID = 
"selected_scenarios";
   protected static final String SELECTED_MPACKS_PROPERTY_ID = 
"selected_mpacks";
 
@@ -77,13 +79,15 @@ public abstract class RegistryAdvisorResourceProvider 
extends AbstractController
    */
   protected RegistryAdvisorRequest createRegistryAdvisorRequest(Request 
request) {
     try {
-      Long registryId = Long.valueOf((String) getRequestProperty(request, 
REGISTRY_ID));
+      Long registryId = Long.valueOf((String) getRequestProperty(request, 
REGISTRY_ID_PROPERTY_ID));
       RegistryAdvisorRequestType requestType = 
RegistryAdvisorRequestType.fromString(
         (String) getRequestProperty(request, getRequestTypePropertyId()));
-      List<String> selectedScenarios = (List<String>) 
getRequestProperty(request, SELECTED_SCENARIOS_PROPERTY_ID);
+      List<ScenarioEntry> selectedScenarios = 
parseSelectedScenariosProperty(request);
       List<MpackEntry> selectedMpacks = parseSelectedMpacksProperty(request);
+      String clusterName = (String) getRequestProperty(request, 
CLUSTER_NAME_PROPERTY_ID);
       return RegistryAdvisorRequestBuilder.forRegistry(registryId)
         .ofType(requestType)
+        .forCluster(clusterName)
         .forScenarios(selectedScenarios)
         .forMpacks(selectedMpacks)
         .build();
@@ -102,7 +106,7 @@ public abstract class RegistryAdvisorResourceProvider 
extends AbstractController
    * @return        List of selected mpacks
    */
   private List<MpackEntry> parseSelectedMpacksProperty(Request request) {
-    List<MpackEntry> selectedMpacks = new 
LinkedList<>();request.getProperties();
+    List<MpackEntry> selectedMpacks = new LinkedList<>();
     Set<Map<String, String>> selectedMpacksProperties =
       (Set<Map<String, String>>) getRequestProperty(request, 
SELECTED_MPACKS_PROPERTY_ID);
     if(selectedMpacksProperties != null) {
@@ -117,6 +121,25 @@ public abstract class RegistryAdvisorResourceProvider 
extends AbstractController
   }
 
   /**
+   * Parse selected scenarios property from the reuqest
+   * @param request {@link Request} input
+   * @return        List of selected scenarios
+   */
+  private List<ScenarioEntry> parseSelectedScenariosProperty(Request request) {
+    List<ScenarioEntry> selectedScenarios = new LinkedList<>();
+    Set<Map<String, String>> selectedScenariosProperties =
+      (Set<Map<String, String>>) getRequestProperty(request, 
SELECTED_SCENARIOS_PROPERTY_ID);
+    if(selectedScenariosProperties != null) {
+      for (Map<String, String> properties : selectedScenariosProperties) {
+        String scenarioName = properties.get("scenario_name");
+        ScenarioEntry scenarioEntry = new ScenarioEntry(scenarioName);
+        selectedScenarios.add(scenarioEntry);
+      }
+    }
+    return selectedScenarios;
+  }
+
+  /**
    * Get value of property in the request
    * @param request       {@link Request} input
    * @param propertyName  Property name

http://git-wip-us.apache.org/repos/asf/ambari/blob/7e967d4f/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryRecommendationResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryRecommendationResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryRecommendationResourceProvider.java
index e2b8ea6..e88ace2 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryRecommendationResourceProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryRecommendationResourceProvider.java
@@ -48,7 +48,7 @@ public class RegistryRecommendationResourceProvider extends 
RegistryAdvisorResou
     .getPropertyId("recommendations", "mpack_bundles");
 
   private static Set<String> pkPropertyIds = new HashSet<>(
-    Arrays.asList(REGISTRY_ID, RECOMMENDATION_ID_PROPERTY_ID));
+    Arrays.asList(REGISTRY_ID_PROPERTY_ID, RECOMMENDATION_ID_PROPERTY_ID));
 
   /**
    * The property ids for a software registry resource.
@@ -62,14 +62,16 @@ public class RegistryRecommendationResourceProvider extends 
RegistryAdvisorResou
 
   static {
     // properties
-    PROPERTY_IDS.add(REGISTRY_ID);
+    PROPERTY_IDS.add(REGISTRY_ID_PROPERTY_ID);
     PROPERTY_IDS.add(RECOMMENDATION_ID_PROPERTY_ID);
     PROPERTY_IDS.add(RECOMMEND_PROPERTY_ID);
+    PROPERTY_IDS.add(CLUSTER_NAME_PROPERTY_ID);
     PROPERTY_IDS.add(SELECTED_SCENARIOS_PROPERTY_ID);
+    PROPERTY_IDS.add(SELECTED_MPACKS_PROPERTY_ID);
     PROPERTY_IDS.add(RECOMMEND_MPACK_BUNDLES_PROPERTY_ID);
 
     // keys
-    KEY_PROPERTY_IDS.put(Resource.Type.Registry, REGISTRY_ID);
+    KEY_PROPERTY_IDS.put(Resource.Type.Registry, REGISTRY_ID_PROPERTY_ID);
     KEY_PROPERTY_IDS.put(Resource.Type.RegistryRecommendation, 
RECOMMENDATION_ID_PROPERTY_ID);
 
   }
@@ -105,10 +107,11 @@ public class RegistryRecommendationResourceProvider 
extends RegistryAdvisorResou
       }
     });
     Resource resource = new ResourceImpl(Resource.Type.RegistryRecommendation);
-    resource.setProperty(REGISTRY_ID, response.getRegistryId());
+    resource.setProperty(REGISTRY_ID_PROPERTY_ID, response.getRegistryId());
     resource.setProperty(RECOMMENDATION_ID_PROPERTY_ID, response.getId());
     resource.setProperty(RECOMMEND_PROPERTY_ID, 
response.getRequestType().toString());
     resource.setProperty(SELECTED_SCENARIOS_PROPERTY_ID, 
response.getSelectedScenarios());
+    resource.setProperty(SELECTED_MPACKS_PROPERTY_ID, 
response.getSelectedMpacks());
     resource.setProperty(RECOMMEND_MPACK_BUNDLES_PROPERTY_ID, 
response.getRecommendations().getMpackBundles());
 
     Set<Resource> associatedResources = new HashSet<>(Arrays.asList(resource));

http://git-wip-us.apache.org/repos/asf/ambari/blob/7e967d4f/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryValidationResourceProvider.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryValidationResourceProvider.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryValidationResourceProvider.java
index bedbb04..006efa9 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryValidationResourceProvider.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RegistryValidationResourceProvider.java
@@ -35,7 +35,6 @@ import 
org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.registry.RegistryAdvisorRequest;
 import org.apache.ambari.server.registry.RegistryValidationResponse;
 
-
 /**
  * Registry validation resource provider
  */
@@ -44,10 +43,10 @@ public class RegistryValidationResourceProvider extends 
RegistryAdvisorResourceP
   protected static final String VALIDATE_PROPERTY_ID = "validate";
   protected static final String VALIDATION_ID_PROPERTY_ID = 
PropertyHelper.getPropertyId(
     "RegistryValidation", "id");
-  protected static final String ITEMS_PROPERTY_ID = "items";
+  protected static final String VALIDATION_RESULTS_PROPERTY_ID = "results";
 
   private static Set<String> pkPropertyIds = new HashSet<>(
-    Arrays.asList(REGISTRY_ID, VALIDATION_ID_PROPERTY_ID));
+    Arrays.asList(REGISTRY_ID_PROPERTY_ID, VALIDATION_ID_PROPERTY_ID));
 
   /**
    * The property ids for a software registry resource.
@@ -61,15 +60,16 @@ public class RegistryValidationResourceProvider extends 
RegistryAdvisorResourceP
 
   static {
     // properties
-    PROPERTY_IDS.add(REGISTRY_ID);
+    PROPERTY_IDS.add(REGISTRY_ID_PROPERTY_ID);
     PROPERTY_IDS.add(VALIDATION_ID_PROPERTY_ID);
     PROPERTY_IDS.add(VALIDATE_PROPERTY_ID);
+    PROPERTY_IDS.add(CLUSTER_NAME_PROPERTY_ID);
     PROPERTY_IDS.add(SELECTED_SCENARIOS_PROPERTY_ID);
     PROPERTY_IDS.add(SELECTED_MPACKS_PROPERTY_ID);
-    PROPERTY_IDS.add(ITEMS_PROPERTY_ID);
+    PROPERTY_IDS.add(VALIDATION_RESULTS_PROPERTY_ID);
 
     // keys
-    KEY_PROPERTY_IDS.put(Resource.Type.Registry, REGISTRY_ID);
+    KEY_PROPERTY_IDS.put(Resource.Type.Registry, REGISTRY_ID_PROPERTY_ID);
     KEY_PROPERTY_IDS.put(Resource.Type.RegistryValidation, 
VALIDATION_ID_PROPERTY_ID);
 
   }
@@ -101,12 +101,12 @@ public class RegistryValidationResourceProvider extends 
RegistryAdvisorResourceP
       }
     });
     Resource resource = new ResourceImpl(Resource.Type.RegistryValidation);
-    setResourceProperty(resource, REGISTRY_ID, response.getRegistryId(), 
getPropertyIds());
+    setResourceProperty(resource, REGISTRY_ID_PROPERTY_ID, 
response.getRegistryId(), getPropertyIds());
     setResourceProperty(resource, VALIDATION_ID_PROPERTY_ID, response.getId(), 
getPropertyIds());
     setResourceProperty(resource, VALIDATE_PROPERTY_ID, 
response.getRequestType().toString(), getPropertyIds());
     setResourceProperty(resource, SELECTED_SCENARIOS_PROPERTY_ID, 
response.getSelectedScenarios(), getPropertyIds());
     setResourceProperty(resource, SELECTED_MPACKS_PROPERTY_ID, 
response.getSelectedMpacks(), getPropertyIds());
-    setResourceProperty(resource, ITEMS_PROPERTY_ID, response.getItems(), 
getPropertyIds());
+    setResourceProperty(resource, VALIDATION_RESULTS_PROPERTY_ID, 
response.getValidationResults(), getPropertyIds());
 
     Set<Resource> associatedResources = new HashSet<>(Arrays.asList(resource));
     return getRequestStatus(null, associatedResources);

http://git-wip-us.apache.org/repos/asf/ambari/blob/7e967d4f/ambari-server/src/main/java/org/apache/ambari/server/registry/MpackBundle.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/registry/MpackBundle.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/MpackBundle.java
new file mode 100644
index 0000000..d00ff33
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/MpackBundle.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.registry;
+
+import java.util.Collection;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ *  Mpack bundle representation
+ */
+public class MpackBundle {
+  private Long rank;
+
+  private Collection<MpackEntry> mpackEntries;
+
+  public MpackBundle(Long rank, Collection<MpackEntry> mpackEntries) {
+    this.rank = rank;
+    this.mpackEntries = mpackEntries;
+  }
+
+  /**
+   * Get ranking
+   * @return
+   */
+  @JsonProperty("rank")
+  public Long getRank() {
+    return rank;
+  }
+
+  /**
+   * Get mpack name
+   * @return
+   */
+  @JsonProperty("mpacks")
+  public Collection<MpackEntry> getMpacks() {
+    return mpackEntries;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/7e967d4f/ambari-server/src/main/java/org/apache/ambari/server/registry/MpackEntry.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/registry/MpackEntry.java 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/MpackEntry.java
index c1029af..47d05c0 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/registry/MpackEntry.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/MpackEntry.java
@@ -21,7 +21,7 @@ import org.codehaus.jackson.annotate.JsonIgnore;
 import org.codehaus.jackson.annotate.JsonProperty;
 
 /**
- *  Mpack version recommenation
+ *  Mpack recommendation entry
  */
 public class MpackEntry {
   private String mpackName;
@@ -44,7 +44,7 @@ public class MpackEntry {
   }
 
   /**
-   * Get version
+   * Get mpack version
    * @return
    */
   @JsonProperty("mpack_version")

http://git-wip-us.apache.org/repos/asf/ambari/blob/7e967d4f/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisor.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisor.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisor.java
index 025338d..9d772ec 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisor.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisor.java
@@ -18,6 +18,7 @@
 package org.apache.ambari.server.registry;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -31,15 +32,14 @@ import org.apache.ambari.server.ObjectNotFoundException;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import 
org.apache.ambari.server.registry.RegistryRecommendationResponse.RegistryRecommendationResponseBuilder;
 import 
org.apache.ambari.server.registry.RegistryRecommendationResponse.RegistryRecommendations;
-import 
org.apache.ambari.server.registry.RegistryValidationResponse.RegistryValidationItem;
 import 
org.apache.ambari.server.registry.RegistryValidationResponse.RegistryValidationResponseBuilder;
+import 
org.apache.ambari.server.registry.RegistryValidationResponse.RegistryValidationResult;
 import org.apache.ambari.server.utils.SetUtils;
 import org.apache.ambari.server.utils.VersionUtils;
 
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
-
 /**
  * Registry Advisor
  */
@@ -88,7 +88,7 @@ public class RegistryAdvisor {
               return false;
             }
             if(maxVersion != null && !maxVersion.isEmpty()
-              && VersionUtils.compareVersions(selectedVersion, maxVersion) > 
0) {
+              && VersionUtils.compareVersions(selectedVersion, maxVersion) >= 
0) {
               return false;
             }
           }
@@ -101,15 +101,16 @@ public class RegistryAdvisor {
   /**
    * Get merged list of mpacks that support the selected scenarios.
    * @param registry      registry to use for getting list of mpacks for 
selected scenarios
-   * @param scenarioNames selected scenario names
+   * @param selectedScenarios selected scenario names
    * @return              merged list of scenario mpacks
    * @throws AmbariException
    */
-  private Collection<String> getScenarioMpacks(Registry registry, 
Collection<String> scenarioNames)
+  private Collection<String> getScenarioMpacks(Registry registry, 
Collection<ScenarioEntry> selectedScenarios)
     throws AmbariException {
     Set<String> scenarioMpackNames = new HashSet<>();
-    for(String selectedScenario : scenarioNames) {
-      RegistryScenario registryScenario = 
registry.getRegistryScenario(selectedScenario);
+    for(ScenarioEntry selectedScenario : selectedScenarios) {
+      RegistryScenario registryScenario = 
registry.getRegistryScenario(selectedScenario.getScenarioName());
+      selectedScenario.setRegistryScenario(registryScenario);
       for(RegistryScenarioMpack scenarioMpack : 
registryScenario.getScenarioMpacks()) {
         if(!scenarioMpackNames.contains(scenarioMpack.getName())) {
           scenarioMpackNames.add(scenarioMpack.getName());
@@ -164,7 +165,7 @@ public class RegistryAdvisor {
    */
   private HashMap<String, MpackEntry> 
convertToMpacksMap(Collection<MpackEntry> mpackEntries) {
     HashMap<String, MpackEntry> mpacksMap = new HashMap<>();
-    for(MpackEntry mpackEntry : mpackEntries) {
+    for (MpackEntry mpackEntry : mpackEntries) {
       String key = mpackEntry.getMpackName();
       mpacksMap.put(key, mpackEntry);
     }
@@ -181,7 +182,7 @@ public class RegistryAdvisor {
     List<Collection<MpackEntry>> compatibleMpackBundles, 
Collection<MpackEntry> selectedMpacks) {
 
     HashMap<String, MpackEntry> selectedMpacksMap = 
convertToMpackVersionsMap(selectedMpacks);
-    for(Collection<MpackEntry> compatibleMpackBundle : compatibleMpackBundles) 
{
+    for (Collection<MpackEntry> compatibleMpackBundle : 
compatibleMpackBundles) {
       boolean isCompatible = true;
       for(MpackEntry mpackEntry: compatibleMpackBundle) {
         String key = mpackEntry.getMpackName() + "-" + 
mpackEntry.getMpackVersion();
@@ -203,12 +204,29 @@ public class RegistryAdvisor {
   }
 
   /**
-   * Returns registry recommendation response based on the request 
[scenario-mpacks]
-   * @param request the recommendation request
-   * @return        {@link RegistryRecommendationResponse} for the request
+   * Returns registry recommendation response based on the request 
[scenario-mpacks, upgrade-mpacks]
+   * @param   request the recommendation request
+   * @return  {@link RegistryRecommendationResponse} for the request
    * @throws AmbariException
    */
   public synchronized RegistryRecommendationResponse 
recommend(RegistryAdvisorRequest request) throws AmbariException {
+    switch(request.getRequestType()) {
+      case SCENARIO_MPACKS:
+        return recommendScenarioMpacks(request);
+      case UPGRADE_MPACKS:
+        return recommendUpgradeMpacks(request);
+      default:
+        throw new AmbariException("Unkown request type");
+    }
+  }
+
+  /**
+   * Returns registry recommendation response for a request of type 
"scenario-mpacks"
+   * @param   request the recommendation response
+   * @return  {@link RegistryRecommendationResponse} for the request
+   * @throws  AmbariException
+   */
+  private RegistryRecommendationResponse 
recommendScenarioMpacks(RegistryAdvisorRequest request) throws AmbariException {
     // Get registry
     Registry registry = 
managementController.getRegistry(request.getRegistryId());
     // Get all scenario mpacks
@@ -241,9 +259,74 @@ public class RegistryAdvisor {
         return o2Wins - o1Wins;
       }
     });
+    Long rank = 1L;
+    List<MpackBundle> mpackBundles = new LinkedList<>();
+    for(Collection<MpackEntry> mpackEntries : compatibleMpackBundles) {
+      MpackBundle mpackBundle = new MpackBundle(rank++, mpackEntries);
+      mpackBundles.add(mpackBundle);
+    }
     // Create recommendations
     RegistryRecommendations recommendations = new RegistryRecommendations();
-    recommendations.setMpackBundles(compatibleMpackBundles);
+    recommendations.setMpackBundles(mpackBundles);
+    return 
RegistryRecommendationResponseBuilder.forRegistry(request.getRegistryId())
+      .ofType(request.getRequestType())
+      .forScenarios(request.getSelectedScenarios())
+      .forMpacks(request.getSelectedMpacks())
+      .withId(generateRequestId())
+      .withRecommendations(recommendations).build();
+  }
+
+  /**
+   * Returns registry recommendation response for a request of type 
"upgrade-mpacks"
+   * @param   request the recommendation response
+   * @return  {@link RegistryRecommendationResponse} for the request
+   * @throws  AmbariException
+   */
+  private RegistryRecommendationResponse 
recommendUpgradeMpacks(RegistryAdvisorRequest request) throws AmbariException {
+    Registry registry = 
managementController.getRegistry(request.getRegistryId());
+    List<RegistryValidationResult> validationItems = new LinkedList<>();
+    List<MpackEntry> selectedMpacks = request.getSelectedMpacks();
+
+    if(selectedMpacks == null || selectedMpacks.isEmpty()) {
+      throw new AmbariException("Must select mpack to be upgraded");
+    }
+
+    if(selectedMpacks.size() > 1) {
+      throw new AmbariException("Must select single mpack for upgrade 
recommendations");
+    }
+
+    // TODO: Add logic to get mpacks used by cluster and remove hardcoded logic
+    // Clusters clusters = managementController.getClusters();
+    // Cluster cluster = clusters.getCluster(request.getClusterName());
+    Collection<MpackEntry> currentMpacks = new LinkedList<>();
+    currentMpacks.add(new MpackEntry("HDPCore", "3.1.0"));
+    currentMpacks.add(new MpackEntry("HDS", "4.3.0"));
+
+    String selectedMpackName = selectedMpacks.get(0).getMpackName();
+    HashMap<String, MpackEntry> currentMpacksMap = 
convertToMpacksMap(currentMpacks);
+    MpackEntry minMpackEntry = currentMpacksMap.get(selectedMpackName);
+
+    RegistryMpack registryMpack = registry.getRegistryMpack(selectedMpackName);
+
+    List<MpackBundle> mpackBundles = new LinkedList<>();
+    Long rank = 1L;
+    List<RegistryMpackVersion> registryMpackVersions = 
(List<RegistryMpackVersion>) registryMpack.getMpackVersions();
+    registryMpackVersions.sort(new Comparator<RegistryMpackVersion>() {
+      @Override
+      public int compare(final RegistryMpackVersion o1, final 
RegistryMpackVersion o2) {
+        return -1 * VersionUtils.compareVersions(o1.getMpackVersion(), 
o2.getMpackVersion());
+      }
+    });
+    for(RegistryMpackVersion registryMpackVersion : registryMpackVersions) {
+      if(VersionUtils.compareVersions(registryMpackVersion.getMpackVersion(), 
minMpackEntry.getMpackVersion()) > 0) {
+        MpackEntry mpackEntry = new MpackEntry(selectedMpackName, 
registryMpackVersion.getMpackVersion());
+        MpackBundle mpackBundle = new MpackBundle(rank++, 
Collections.singletonList(mpackEntry));
+        mpackBundles.add(mpackBundle);
+      }
+    }
+
+    RegistryRecommendations recommendations = new RegistryRecommendations();
+    recommendations.setMpackBundles(mpackBundles);
     return 
RegistryRecommendationResponseBuilder.forRegistry(request.getRegistryId())
       .ofType(request.getRequestType())
       .forScenarios(request.getSelectedScenarios())
@@ -259,8 +342,26 @@ public class RegistryAdvisor {
    * @throws AmbariException
    */
   public synchronized RegistryValidationResponse 
validate(RegistryAdvisorRequest request) throws AmbariException {
+
+    switch(request.getRequestType()) {
+      case SCENARIO_MPACKS:
+        return validateScenarioMpacks(request);
+      case UPGRADE_MPACKS:
+        return validateUpgradeMpacks(request);
+      default:
+        throw new AmbariException("Unkown request type");
+    }
+  }
+
+  /**
+   * Returns registry validation response based on the request of type 
"scenario-mpacks"
+   * @param request the validation request
+   * @return        {@link RegistryValidationResponse} for the request
+   * @throws AmbariException
+   */
+  private RegistryValidationResponse 
validateScenarioMpacks(RegistryAdvisorRequest request) throws AmbariException {
     Registry registry = 
managementController.getRegistry(request.getRegistryId());
-    List<RegistryValidationItem> validationItems = new LinkedList<>();
+    List<RegistryValidationResult> validationItems = new LinkedList<>();
 
     // Get all mpacks required for the selected scenarios
     Collection<String> scenarioMpackNames = getScenarioMpacks(registry, 
request.getSelectedScenarios());
@@ -280,7 +381,7 @@ public class RegistryAdvisor {
         String level = "FATAL";
         String message = "Selected mpacks does not contain " + mpackName +
           " mpack which is required for supporting the selected scenarios.";
-        RegistryValidationItem validationItem = new 
RegistryValidationItem(type, level, message);
+        RegistryValidationResult validationItem = new 
RegistryValidationResult(type, level, message);
         validationItems.add(validationItem);
       }
     }
@@ -298,7 +399,7 @@ public class RegistryAdvisor {
         String mpackFullName = mpackEntry.getMpackName() + "-" + 
mpackEntry.getMpackVersion();
         String message = "Mpack " + mpackFullName + " not found in the 
registry. "
           + "Cannot validate compatility with other mpacks.";
-        RegistryValidationItem validationItem = new 
RegistryValidationItem(type, level, message);
+        RegistryValidationResult validationItem = new 
RegistryValidationResult(type, level, message);
         validationItems.add(validationItem);
       }
     }
@@ -317,7 +418,7 @@ public class RegistryAdvisor {
       String type = "CompatibleMpackValidation";
       String level = "FATAL";
       String message = "Selected mpacks are not compatible and can cause 
issues during cluster installation.";
-      RegistryValidationItem validationItem = new RegistryValidationItem(type, 
level, message);
+      RegistryValidationResult validationItem = new 
RegistryValidationResult(type, level, message);
       validationItems.add(validationItem);
     }
 
@@ -330,6 +431,133 @@ public class RegistryAdvisor {
   }
 
   /**
+   * Returns registry validation response based on the request of type 
"upgrade-mpacks"
+   * @param request the validation request
+   * @return        {@link RegistryValidationResponse} for the request
+   * @throws AmbariException
+   */
+  private RegistryValidationResponse 
validateUpgradeMpacks(RegistryAdvisorRequest request) throws AmbariException {
+    Registry registry = 
managementController.getRegistry(request.getRegistryId());
+    List<RegistryValidationResult> validationItems = new LinkedList<>();
+    List<MpackEntry> selectedMpacks = request.getSelectedMpacks();
+
+    if(selectedMpacks == null || selectedMpacks.isEmpty()) {
+      throw new AmbariException("Must select mpack to be upgraded");
+    }
+
+    if(selectedMpacks.size() > 1) {
+      throw new AmbariException("Must select single mpack for upgrade 
validation");
+    }
+
+    // TODO: Add logic to get mpacks used by cluster and remove hardcoded logic
+    // Clusters clusters = managementController.getClusters();
+    // Cluster cluster = clusters.getCluster(request.getClusterName());
+    Collection<MpackEntry> currentMpacks = new LinkedList<>();
+    currentMpacks.add(new MpackEntry("HDPCore", "3.1.0"));
+    currentMpacks.add(new MpackEntry("HDS", "4.3.0"));
+
+    HashMap<String, MpackEntry> currentMpacksMap = 
convertToMpacksMap(currentMpacks);
+
+    // TODO: Add logic for mpacks not in registry
+    List<String> currentMpackNames = new LinkedList<>();
+    for(MpackEntry currentMpack : currentMpacks) {
+      currentMpackNames.add(currentMpack.getMpackName());
+    }
+
+    // Get all mpack versions for each current mpack
+    List<Collection<MpackEntry>> allMpackEntries = 
getAllMpackEntries(registry, currentMpackNames);
+    // Get all possible mpack bundles
+    List<Collection<MpackEntry>> allMpackBundles = 
SetUtils.permutations(allMpackEntries);
+    // Filter down to compatible mpack bundles
+    List<Collection<MpackEntry>> compatibleMpackBundles = 
filterCompatibleMpackBundles(allMpackBundles);
+
+
+    HashMap<String, MpackEntry> selectedMpacksMap = 
convertToMpacksMap(selectedMpacks);
+
+    List<MpackEntry> mergedMpacks = new LinkedList<>();
+    for(String key : currentMpackNames) {
+      if(selectedMpacksMap.containsKey(key)) {
+        mergedMpacks.add(selectedMpacksMap.get(key));
+      } else {
+        mergedMpacks.add(currentMpacksMap.get(key));
+      }
+    }
+
+    Collection<MpackEntry> compatibleMpackBundle = 
findCompatibleMpackBundle(compatibleMpackBundles, mergedMpacks);
+    if(compatibleMpackBundle == null) {
+      // Order recommendations by versions.
+      compatibleMpackBundles.sort(new Comparator<Collection<MpackEntry>>() {
+        @Override
+        public int compare(final Collection<MpackEntry> o1, final 
Collection<MpackEntry> o2) {
+          int o1Wins = 0;
+          int o2Wins = 0;
+          HashMap<String, MpackEntry> o1Map = convertToMpacksMap(o1);
+          HashMap<String, MpackEntry> o2Map = convertToMpacksMap(o2);
+          for(Map.Entry<String, MpackEntry> mapEntry : o1Map.entrySet()) {
+            MpackEntry o1Entry = mapEntry.getValue();
+            MpackEntry o2Entry = o2Map.get(mapEntry.getKey());
+            int compareResult = 
VersionUtils.compareVersions(o1Entry.getMpackVersion(), 
o2Entry.getMpackVersion());
+            if(compareResult > 0) {
+              o1Wins++;
+            } else if(compareResult < 0) {
+              o2Wins++;
+            }
+          }
+          return o1Wins - o2Wins;
+        }
+      });
+
+      boolean noMatchFound = true;
+      for(Collection<MpackEntry> mpackBundle : compatibleMpackBundles) {
+        HashMap<String, MpackEntry> mpackBundleMap = 
convertToMpacksMap(mpackBundle);
+        boolean isMatch = true;
+        for(Map.Entry<String, MpackEntry> selectedEntry : 
selectedMpacksMap.entrySet()) {
+          String selectedKey = selectedEntry.getKey();
+          MpackEntry selectedMpackEntry = selectedEntry.getValue();
+          if (!mpackBundleMap.containsKey(selectedKey) ||
+            
!VersionUtils.areVersionsEqual(selectedMpackEntry.getMpackVersion(),
+              mpackBundleMap.get(selectedKey).getMpackVersion(), true)) {
+            isMatch = false;
+          }
+        }
+        if(isMatch) {
+          for(Map.Entry<String, MpackEntry> bundleEntry :  
mpackBundleMap.entrySet()){
+            if(!selectedMpacksMap.containsKey(bundleEntry.getKey())) {
+              String targetMpackName = bundleEntry.getKey();
+              MpackEntry targetMpackEntry = bundleEntry.getValue();
+              String targetMpackFullName = targetMpackEntry.getMpackName() + 
"-" + targetMpackEntry.getMpackVersion();
+              MpackEntry currentMpackEntry = 
currentMpacksMap.get(targetMpackName);
+              String currentMpackFullName = currentMpackEntry.getMpackName() + 
"-" + currentMpackEntry.getMpackVersion();
+
+              String type = "UpgradeMpackValidation";
+              String level = "WARN";
+              String message = "Mpack " + currentMpackFullName + " needs to be 
upgraded to " + targetMpackFullName;
+              RegistryValidationResult validationItem = new 
RegistryValidationResult(type, level, message);
+              validationItems.add(validationItem);
+            }
+          }
+          noMatchFound = false;
+          break;
+        }
+      }
+      if(noMatchFound) {
+        String type = "UpgradeMpackValidation";
+        String level = "FATAL";
+        String message = "No recommendations for upgrading other mpacks in the 
cluster found.";
+        RegistryValidationResult validationItem = new 
RegistryValidationResult(type, level, message);
+        validationItems.add(validationItem);
+      }
+    }
+
+    return 
RegistryValidationResponseBuilder.forRegistry(request.getRegistryId())
+      .ofType(request.getRequestType())
+      .forScenarios(request.getSelectedScenarios())
+      .forMpacks(request.getSelectedMpacks())
+      .withId(generateRequestId())
+      .withValidations(validationItems).build();
+  }
+
+  /**
    * Generate registry advisor request id
    * TODO: Store registry advisor requests in database.
    * @return

http://git-wip-us.apache.org/repos/asf/ambari/blob/7e967d4f/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorRequest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorRequest.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorRequest.java
index 72e9279..a79ae81 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorRequest.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorRequest.java
@@ -28,7 +28,8 @@ import 
org.apache.ambari.server.exceptions.RegistryAdvisorException;
 public class RegistryAdvisorRequest {
   private Long registryId;
   private RegistryAdvisorRequestType requestType;
-  private List<String> selectedScenarios;
+  private String clusterName;
+  private List<ScenarioEntry> selectedScenarios;
   private List<MpackEntry> selectedMpacks;
 
   /**
@@ -43,11 +44,15 @@ public class RegistryAdvisorRequest {
     return registryId;
   }
 
+  public String getClusterName() {
+    return clusterName;
+  }
+
   public RegistryAdvisorRequestType getRequestType() {
     return requestType;
   }
 
-  public List<String> getSelectedScenarios() {
+  public List<ScenarioEntry> getSelectedScenarios() {
     return selectedScenarios;
   }
 
@@ -74,7 +79,12 @@ public class RegistryAdvisorRequest {
       return this;
     }
 
-    public RegistryAdvisorRequestBuilder forScenarios(List<String> 
selectedScenarios) {
+    public RegistryAdvisorRequestBuilder forCluster(String clusterName) {
+      this.instance.clusterName = clusterName;
+      return this;
+    }
+
+    public RegistryAdvisorRequestBuilder forScenarios(List<ScenarioEntry> 
selectedScenarios) {
       this.instance.selectedScenarios = selectedScenarios;
       return this;
     }
@@ -93,7 +103,8 @@ public class RegistryAdvisorRequest {
    *
    */
   public enum RegistryAdvisorRequestType {
-    SCENARIO_MPACKS("scenario-mpacks");
+    SCENARIO_MPACKS("scenario-mpacks"),
+    UPGRADE_MPACKS("upgrade-mpacks");
 
     private String type;
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/7e967d4f/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorResponse.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorResponse.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorResponse.java
index 38db4c3..ad033ff 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorResponse.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryAdvisorResponse.java
@@ -28,7 +28,7 @@ public abstract class RegistryAdvisorResponse {
   private Long id;
   private Long registryId;
   private RegistryAdvisorRequest.RegistryAdvisorRequestType requestType;
-  private List<String> selectedScenarios;
+  private List<ScenarioEntry> selectedScenarios;
   private List<MpackEntry> selectedMpacks;
 
   /**
@@ -83,7 +83,7 @@ public abstract class RegistryAdvisorResponse {
    * Set selected scenarios
    * @param selectedScenarios
    */
-  public void setSelectedScenarios(List<String> selectedScenarios) {
+  public void setSelectedScenarios(List<ScenarioEntry> selectedScenarios) {
     this.selectedScenarios = selectedScenarios;
   }
 
@@ -91,7 +91,7 @@ public abstract class RegistryAdvisorResponse {
    * Get selected scenarios
    * @return
    */
-  public List<String> getSelectedScenarios() {
+  public List<ScenarioEntry> getSelectedScenarios() {
     return selectedScenarios;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/7e967d4f/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryRecommendationResponse.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryRecommendationResponse.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryRecommendationResponse.java
index 923b409..c5299c8 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryRecommendationResponse.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryRecommendationResponse.java
@@ -17,7 +17,6 @@
  */
 package org.apache.ambari.server.registry;
 
-import java.util.Collection;
 import java.util.List;
 
 import 
org.apache.ambari.server.registry.RegistryAdvisorRequest.RegistryAdvisorRequestType;
@@ -73,7 +72,7 @@ public class RegistryRecommendationResponse extends 
RegistryAdvisorResponse {
       return this;
     }
 
-    public RegistryRecommendationResponseBuilder forScenarios(List<String> 
selectedScenarios) {
+    public RegistryRecommendationResponseBuilder 
forScenarios(List<ScenarioEntry> selectedScenarios) {
       this.instance.setSelectedScenarios(selectedScenarios);
       return this;
     }
@@ -102,13 +101,13 @@ public class RegistryRecommendationResponse extends 
RegistryAdvisorResponse {
    * Registry recommendations
    */
   public static class RegistryRecommendations {
-    public List<Collection<MpackEntry>> mpackBundles;
+    public List<MpackBundle> mpackBundles;
 
-    public void setMpackBundles(List<Collection<MpackEntry>> mpackBundles) {
+    public void setMpackBundles(List<MpackBundle> mpackBundles) {
       this.mpackBundles = mpackBundles;
     }
 
-    public List<Collection<MpackEntry>> getMpackBundles() {
+    public List<MpackBundle> getMpackBundles() {
       return mpackBundles;
     }
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/7e967d4f/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryValidationResponse.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryValidationResponse.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryValidationResponse.java
index ed3b137..937bca3 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryValidationResponse.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/RegistryValidationResponse.java
@@ -29,14 +29,14 @@ import org.codehaus.jackson.annotate.JsonProperty;
 public class RegistryValidationResponse extends  RegistryAdvisorResponse {
 
   @JsonProperty
-  private List<RegistryValidationItem> items;
+  private List<RegistryValidationResult> validationResults;
 
-  public List<RegistryValidationItem> getItems() {
-    return items;
+  public List<RegistryValidationResult> getValidationResults() {
+    return validationResults;
   }
 
-  public void setItems(List<RegistryValidationItem> items) {
-    this.items = items;
+  public void setItems(List<RegistryValidationResult> validationResults) {
+    this.validationResults = validationResults;
   }
   
   /**
@@ -67,7 +67,7 @@ public class RegistryValidationResponse extends  
RegistryAdvisorResponse {
       return this;
     }
 
-    public RegistryValidationResponseBuilder forScenarios(List<String> 
selectedScenarios) {
+    public RegistryValidationResponseBuilder forScenarios(List<ScenarioEntry> 
selectedScenarios) {
       this.instance.setSelectedScenarios(selectedScenarios);
       return this;
     }
@@ -82,8 +82,8 @@ public class RegistryValidationResponse extends  
RegistryAdvisorResponse {
       return this;
     }
 
-    public RegistryValidationResponseBuilder 
withValidations(List<RegistryValidationItem> items) {
-      this.instance.items = items;
+    public RegistryValidationResponseBuilder 
withValidations(List<RegistryValidationResult> validationResults) {
+      this.instance.validationResults = validationResults;
       return this;
     }
 
@@ -95,7 +95,7 @@ public class RegistryValidationResponse extends  
RegistryAdvisorResponse {
   /**
    * Registry validation item
    */
-  public static class RegistryValidationItem {
+  public static class RegistryValidationResult {
     @JsonProperty
     private String type;
 
@@ -105,7 +105,7 @@ public class RegistryValidationResponse extends  
RegistryAdvisorResponse {
     @JsonProperty
     private String message;
 
-    public RegistryValidationItem(String type, String level, String message) {
+    public RegistryValidationResult(String type, String level, String message) 
{
       this.type = type;
       this.level = level;
       this.message = message;

http://git-wip-us.apache.org/repos/asf/ambari/blob/7e967d4f/ambari-server/src/main/java/org/apache/ambari/server/registry/ScenarioEntry.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/registry/ScenarioEntry.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/ScenarioEntry.java
new file mode 100644
index 0000000..d636e1b
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/registry/ScenarioEntry.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.registry;
+
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ *  Scenario recommenation entry
+ */
+public class ScenarioEntry {
+  private String scenarioName;
+  private RegistryScenario registryScenario;
+
+  public ScenarioEntry(String scenarioName) {
+    this.scenarioName = scenarioName;
+  }
+
+  /**
+   * Get scenario name
+   * @return
+   */
+  @JsonProperty("scenario_name")
+  public String getScenarioName() {
+    return scenarioName;
+  }
+
+
+  /**
+   * Set registry scenario
+   * @param registryScenario
+   */
+  public void setRegistryScenario(RegistryScenario registryScenario) {
+    this.registryScenario = registryScenario;
+  }
+
+  /**
+   * Get registry scenario
+   * @return
+   */
+  @JsonIgnore
+  public RegistryScenario getRegistryScenario() {
+    return registryScenario;
+  }
+}

Reply via email to