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; + } +}
