You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sr...@apache.org on 2014/08/26 01:58:16 UTC
git commit: AMBARI-7006. Provide stack_advisor python script for HDP
1.3.x stack versions
Repository: ambari
Updated Branches:
refs/heads/trunk 46a91dbb0 -> fb1e0ca52
AMBARI-7006. Provide stack_advisor python script for HDP 1.3.x stack versions
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/fb1e0ca5
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/fb1e0ca5
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/fb1e0ca5
Branch: refs/heads/trunk
Commit: fb1e0ca5260d35938df2c10cd75ee5a594873c30
Parents: 46a91db
Author: Srimanth Gunturi <sg...@hortonworks.com>
Authored: Mon Aug 25 14:58:14 2014 -0700
Committer: Srimanth Gunturi <sg...@hortonworks.com>
Committed: Mon Aug 25 16:57:54 2014 -0700
----------------------------------------------------------------------
.../server/api/services/AmbariMetaInfo.java | 18 +
.../stackadvisor/StackAdvisorHelper.java | 14 +-
...GetComponentLayoutRecommnedationCommand.java | 5 +-
.../GetComponentLayoutValidationCommand.java | 5 +-
.../GetConfigurationRecommnedationCommand.java | 13 +-
.../GetConfigurationValidationCommand.java | 5 +-
.../commands/StackAdvisorCommand.java | 20 +-
.../src/main/resources/scripts/stack_advisor.py | 5 +-
.../stacks/HDP/1.3.2/services/stack_advisor.py | 519 +++++++++++++++++++
.../stacks/HDP/1.3.3/services/stack_advisor.py | 25 +
.../stacks/HDP/1.3/services/stack_advisor.py | 25 +
.../server/api/services/AmbariMetaInfoTest.java | 9 +
.../stackadvisor/StackAdvisorHelperTest.java | 22 +-
.../commands/StackAdvisorCommandTest.java | 80 ++-
14 files changed, 728 insertions(+), 37 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/fb1e0ca5/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
index 80af575..56b866d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariMetaInfo.java
@@ -645,6 +645,24 @@ public class AmbariMetaInfo {
return stackInfoResult;
}
+ public List<String> getStackParentVersions(String stackName, String version) {
+ List<String> parents = new ArrayList<String>();
+ try {
+ StackInfo stackInfo = getStackInfo(stackName, version);
+ if (stackInfo != null) {
+ String parentVersion = stackInfo.getParentStackVersion();
+ if (parentVersion != null) {
+ parents.add(parentVersion);
+ parents.addAll(getStackParentVersions(stackName, parentVersion));
+ }
+ }
+ } catch (AmbariException e) {
+ // parent was not found. just returning empty list
+ } finally {
+ return parents;
+ }
+ }
+
public Set<PropertyInfo> getProperties(String stackName, String version, String serviceName)
throws AmbariException {
http://git-wip-us.apache.org/repos/asf/ambari/blob/fb1e0ca5/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java
index 6903c1d..60cdd52 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelper.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.api.services.stackadvisor;
import java.io.File;
import java.io.IOException;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest.StackAdvisorRequestType;
import org.apache.ambari.server.api.services.stackadvisor.commands.GetComponentLayoutRecommnedationCommand;
import org.apache.ambari.server.api.services.stackadvisor.commands.GetComponentLayoutValidationCommand;
@@ -39,16 +40,19 @@ public class StackAdvisorHelper {
private File recommendationsDir;
private String stackAdvisorScript;
+ private final AmbariMetaInfo metaInfo;
/* Monotonically increasing requestid */
private int requestId = 0;
private StackAdvisorRunner saRunner;
@Inject
- public StackAdvisorHelper(Configuration conf, StackAdvisorRunner saRunner) throws IOException {
+ public StackAdvisorHelper(Configuration conf, StackAdvisorRunner saRunner,
+ AmbariMetaInfo metaInfo) throws IOException {
this.recommendationsDir = conf.getRecommendationsDir();
this.stackAdvisorScript = conf.getStackAdvisorScript();
this.saRunner = saRunner;
+ this.metaInfo = metaInfo;
}
/**
@@ -74,10 +78,10 @@ public class StackAdvisorHelper {
StackAdvisorCommand<ValidationResponse> command;
if (requestType == StackAdvisorRequestType.HOST_GROUPS) {
command = new GetComponentLayoutValidationCommand(recommendationsDir, stackAdvisorScript,
- requestId, saRunner);
+ requestId, saRunner, metaInfo);
} else if (requestType == StackAdvisorRequestType.CONFIGURATIONS) {
command = new GetConfigurationValidationCommand(recommendationsDir, stackAdvisorScript,
- requestId, saRunner);
+ requestId, saRunner, metaInfo);
} else {
throw new StackAdvisorException(String.format("Unsupported request type, type=%s",
requestType));
@@ -109,10 +113,10 @@ public class StackAdvisorHelper {
StackAdvisorCommand<RecommendationResponse> command;
if (requestType == StackAdvisorRequestType.HOST_GROUPS) {
command = new GetComponentLayoutRecommnedationCommand(recommendationsDir, stackAdvisorScript,
- requestId, saRunner);
+ requestId, saRunner, metaInfo);
} else if (requestType == StackAdvisorRequestType.CONFIGURATIONS) {
command = new GetConfigurationRecommnedationCommand(recommendationsDir, stackAdvisorScript,
- requestId, saRunner);
+ requestId, saRunner, metaInfo);
} else {
throw new StackAdvisorException(String.format("Unsupported request type, type=%s",
requestType));
http://git-wip-us.apache.org/repos/asf/ambari/blob/fb1e0ca5/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutRecommnedationCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutRecommnedationCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutRecommnedationCommand.java
index 6e7533a..b91f912 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutRecommnedationCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutRecommnedationCommand.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.api.services.stackadvisor.commands;
import java.io.File;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
@@ -33,8 +34,8 @@ public class GetComponentLayoutRecommnedationCommand extends
StackAdvisorCommand<RecommendationResponse> {
public GetComponentLayoutRecommnedationCommand(File recommendationsDir,
- String stackAdvisorScript, int requestId, StackAdvisorRunner saRunner) {
- super(recommendationsDir, stackAdvisorScript, requestId, saRunner);
+ String stackAdvisorScript, int requestId, StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
+ super(recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
}
@Override
http://git-wip-us.apache.org/repos/asf/ambari/blob/fb1e0ca5/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutValidationCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutValidationCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutValidationCommand.java
index a5453f6..1a1fc98 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutValidationCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetComponentLayoutValidationCommand.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.api.services.stackadvisor.commands;
import java.io.File;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
@@ -31,8 +32,8 @@ import org.apache.ambari.server.api.services.stackadvisor.validations.Validation
public class GetComponentLayoutValidationCommand extends StackAdvisorCommand<ValidationResponse> {
public GetComponentLayoutValidationCommand(File recommendationsDir, String stackAdvisorScript,
- int requestId, StackAdvisorRunner saRunner) {
- super(recommendationsDir, stackAdvisorScript, requestId, saRunner);
+ int requestId, StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
+ super(recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
}
@Override
http://git-wip-us.apache.org/repos/asf/ambari/blob/fb1e0ca5/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationRecommnedationCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationRecommnedationCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationRecommnedationCommand.java
index e65f97f..52df3d0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationRecommnedationCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationRecommnedationCommand.java
@@ -18,6 +18,7 @@
package org.apache.ambari.server.api.services.stackadvisor.commands;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
@@ -37,9 +38,9 @@ import java.util.Set;
public class GetConfigurationRecommnedationCommand extends
StackAdvisorCommand<RecommendationResponse> {
- public GetConfigurationRecommnedationCommand(File recommendationsDir,
- String stackAdvisorScript, int requestId, StackAdvisorRunner saRunner) {
- super(recommendationsDir, stackAdvisorScript, requestId, saRunner);
+ public GetConfigurationRecommnedationCommand(File recommendationsDir, String stackAdvisorScript, int requestId,
+ StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
+ super(recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
}
@Override
@@ -56,12 +57,6 @@ public class GetConfigurationRecommnedationCommand extends
}
@Override
- protected StackAdvisorData adjust(StackAdvisorData data, StackAdvisorRequest request) {
- // do nothing
- return data;
- }
-
- @Override
protected RecommendationResponse updateResponse(StackAdvisorRequest request, RecommendationResponse response) {
response.getRecommendations().getBlueprint().setHostGroups(processHostGroups(request));
response.getRecommendations().getBlueprintClusterBinding().setHostGroups(processHostGroupBindings(request));
http://git-wip-us.apache.org/repos/asf/ambari/blob/fb1e0ca5/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationValidationCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationValidationCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationValidationCommand.java
index 2cd6481..36fe6cb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationValidationCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/GetConfigurationValidationCommand.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.api.services.stackadvisor.commands;
import java.io.File;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
@@ -31,8 +32,8 @@ import org.apache.ambari.server.api.services.stackadvisor.validations.Validation
public class GetConfigurationValidationCommand extends StackAdvisorCommand<ValidationResponse> {
public GetConfigurationValidationCommand(File recommendationsDir, String stackAdvisorScript,
- int requestId, StackAdvisorRunner saRunner) {
- super(recommendationsDir, stackAdvisorScript, requestId, saRunner);
+ int requestId, StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
+ super(recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
}
@Override
http://git-wip-us.apache.org/repos/asf/ambari/blob/fb1e0ca5/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java
index 607e337..81d4605 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java
@@ -35,6 +35,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.api.services.BaseService;
import org.apache.ambari.server.api.services.LocalUriInfo;
import org.apache.ambari.server.api.services.Request;
@@ -52,6 +53,7 @@ import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;
+import org.codehaus.jackson.node.TextNode;
/**
* Parent for all commands.
@@ -89,9 +91,11 @@ public abstract class StackAdvisorCommand<T> extends BaseService {
protected ObjectMapper mapper;
+ private final AmbariMetaInfo metaInfo;
+
@SuppressWarnings("unchecked")
public StackAdvisorCommand(File recommendationsDir, String stackAdvisorScript, int requestId,
- StackAdvisorRunner saRunner) {
+ StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
this.type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
@@ -102,6 +106,7 @@ public abstract class StackAdvisorCommand<T> extends BaseService {
this.stackAdvisorScript = stackAdvisorScript;
this.requestId = requestId;
this.saRunner = saRunner;
+ this.metaInfo = metaInfo;
}
protected abstract StackAdvisorCommandType getCommandType();
@@ -133,6 +138,7 @@ public abstract class StackAdvisorCommand<T> extends BaseService {
try {
ObjectNode root = (ObjectNode) this.mapper.readTree(data.servicesJSON);
+ populateStackHierarchy(root);
populateComponentHostsMap(root, request.getComponentHostsMap());
populateConfigurations(root, request.getConfigurations());
@@ -166,6 +172,18 @@ public abstract class StackAdvisorCommand<T> extends BaseService {
}
}
+ protected void populateStackHierarchy(ObjectNode root) {
+ ObjectNode version = (ObjectNode) root.get("Versions");
+ TextNode stackName = (TextNode) version.get("stack_name");
+ TextNode stackVersion = (TextNode) version.get("stack_version");
+ ObjectNode stackHierarchy = version.putObject("stack_hierarchy");
+ stackHierarchy.put("stack_name", stackName);
+ ArrayNode parents = stackHierarchy.putArray("stack_versions");
+ for (String parentVersion : metaInfo.getStackParentVersions(stackName.asText(), stackVersion.asText())) {
+ parents.add(parentVersion);
+ }
+ }
+
private void populateComponentHostsMap(ObjectNode root, Map<String, Set<String>> componentHostsMap) {
ArrayNode services = (ArrayNode) root.get(SERVICES_PROPETRY);
Iterator<JsonNode> servicesIter = services.getElements();
http://git-wip-us.apache.org/repos/asf/ambari/blob/fb1e0ca5/ambari-server/src/main/resources/scripts/stack_advisor.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/scripts/stack_advisor.py b/ambari-server/src/main/resources/scripts/stack_advisor.py
index 05d3a20..61d1e09 100755
--- a/ambari-server/src/main/resources/scripts/stack_advisor.py
+++ b/ambari-server/src/main/resources/scripts/stack_advisor.py
@@ -82,9 +82,8 @@ def main(argv=None):
stackName = services["Versions"]["stack_name"]
stackVersion = services["Versions"]["stack_version"]
parentVersions = []
- if "parent_stack_version" in services["Versions"] and \
- services["Versions"]["parent_stack_version"] is not None:
- parentVersions = [ services["Versions"]["parent_stack_version"] ]
+ if "stack_hierarchy" in services["Versions"]:
+ parentVersions = services["Versions"]["stack_hierarchy"]["stack_versions"]
stackAdvisor = instantiateStackAdvisor(stackName, stackVersion, parentVersions)
http://git-wip-us.apache.org/repos/asf/ambari/blob/fb1e0ca5/ambari-server/src/main/resources/stacks/HDP/1.3.2/services/stack_advisor.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/1.3.2/services/stack_advisor.py b/ambari-server/src/main/resources/stacks/HDP/1.3.2/services/stack_advisor.py
new file mode 100644
index 0000000..f3c1e1d
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/1.3.2/services/stack_advisor.py
@@ -0,0 +1,519 @@
+#!/usr/bin/env ambari-python-wrap
+"""
+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
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+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.
+"""
+
+import re
+import socket
+import sys
+
+from stack_advisor import StackAdvisor
+
+class HDP132StackAdvisor(StackAdvisor):
+
+ def recommendComponentLayout(self, services, hosts):
+ """
+ Returns Services object with hostnames array populated for components
+ If hostnames are populated for some components (partial blueprint) - these components will not be processed
+ """
+ stackName = services["Versions"]["stack_name"]
+ stackVersion = services["Versions"]["stack_version"]
+ hostsList = [host["Hosts"]["host_name"] for host in hosts["items"]]
+ servicesList = [service["StackServices"]["service_name"] for service in services["services"]]
+
+ recommendations = {
+ "Versions": {"stack_name": stackName, "stack_version": stackVersion},
+ "hosts": hostsList,
+ "services": servicesList,
+ "recommendations": {
+ "blueprint": {
+ "host_groups": [ ]
+ },
+ "blueprint_cluster_binding": {
+ "host_groups": [ ]
+ }
+ }
+ }
+
+ hostsComponentsMap = {}
+
+ #extend 'hostsComponentsMap' with MASTER components
+ for service in services["services"]:
+ masterComponents = [component for component in service["components"] if isMaster(component)]
+ for component in masterComponents:
+ componentName = component["StackServiceComponents"]["component_name"]
+ hostsForComponent = []
+
+ if isAlreadyPopulated(component):
+ hostsForComponent = component["StackServiceComponents"]["hostnames"]
+ else:
+ availableHosts = hostsList
+ if len(hostsList) > 1 and self.isNotPreferableOnAmbariServerHost(component):
+ availableHosts = [hostName for hostName in hostsList if not isLocalHost(hostName)]
+
+ if isMasterWithMultipleInstances(component):
+ hostsCount = defaultNoOfMasterHosts(component)
+ if hostsCount > 1: # get first 'hostsCount' available hosts
+ if len(availableHosts) < hostsCount:
+ hostsCount = len(availableHosts)
+ hostsForComponent = availableHosts[:hostsCount]
+ else:
+ hostsForComponent = [self.getHostForComponent(component, availableHosts)]
+ else:
+ hostsForComponent = [self.getHostForComponent(component, availableHosts)]
+
+ #extend 'hostsComponentsMap' with 'hostsForComponent'
+ for hostName in hostsForComponent:
+ if hostName not in hostsComponentsMap:
+ hostsComponentsMap[hostName] = []
+ hostsComponentsMap[hostName].append( { "name":componentName } )
+
+ #extend 'hostsComponentsMap' with Slave and Client Components
+ componentsListList = [service["components"] for service in services["services"]]
+ componentsList = [item for sublist in componentsListList for item in sublist]
+ usedHostsListList = [component["StackServiceComponents"]["hostnames"] for component in componentsList if not self.isNotValuable(component)]
+ utilizedHosts = [item for sublist in usedHostsListList for item in sublist]
+ freeHosts = [hostName for hostName in hostsList if hostName not in utilizedHosts]
+
+ for service in services["services"]:
+ slaveClientComponents = [component for component in service["components"] if isSlave(component) or isClient(component)]
+ for component in slaveClientComponents:
+ componentName = component["StackServiceComponents"]["component_name"]
+ hostsForComponent = []
+
+ if isAlreadyPopulated(component):
+ hostsForComponent = component["StackServiceComponents"]["hostnames"]
+ elif component["StackServiceComponents"]["cardinality"] == "ALL":
+ hostsForComponent = hostsList
+ else:
+ if len(freeHosts) == 0:
+ hostsForComponent = hostsList[-1:]
+ else: # len(freeHosts) >= 1
+ hostsForComponent = freeHosts
+ if isClient(component):
+ hostsForComponent = freeHosts[0:1]
+
+ #extend 'hostsComponentsMap' with 'hostsForComponent'
+ for hostName in hostsForComponent:
+ if hostName not in hostsComponentsMap:
+ hostsComponentsMap[hostName] = []
+ hostsComponentsMap[hostName].append( { "name": componentName } )
+
+ #prepare 'host-group's from 'hostsComponentsMap'
+ host_groups = recommendations["recommendations"]["blueprint"]["host_groups"]
+ bindings = recommendations["recommendations"]["blueprint_cluster_binding"]["host_groups"]
+ index = 0
+ for key in hostsComponentsMap.keys():
+ index += 1
+ host_group_name = "host-group-{0}".format(index)
+ host_groups.append( { "name": host_group_name, "components": hostsComponentsMap[key] } )
+ bindings.append( { "name": host_group_name, "hosts": [{ "fqdn": socket.getfqdn(key) }] } )
+
+ return recommendations
+ pass
+
+ def getHostForComponent(self, component, hostsList):
+ componentName = component["StackServiceComponents"]["component_name"]
+ scheme = self.defineSelectionScheme(componentName)
+
+ if len(hostsList) == 1:
+ return hostsList[0]
+ else:
+ for key in scheme.keys():
+ if isinstance(key, ( int, long )):
+ if len(hostsList) < key:
+ return hostsList[scheme[key]]
+ return hostsList[scheme['else']]
+
+ def defineSelectionScheme(self, componentName):
+ scheme = self.selectionScheme(componentName)
+ if scheme is None:
+ scheme = {"else": 0}
+ return scheme
+
+ def selectionScheme(self, componentName):
+ return {
+ 'NAMENODE': {"else": 0},
+ 'SECONDARY_NAMENODE': {"else": 1},
+ 'HBASE_MASTER': {6: 0, 31: 2, "else": 3},
+
+ 'HISTORYSERVER': {31: 1, "else": 2},
+ 'RESOURCEMANAGER': {31: 1, "else": 2},
+
+ 'OOZIE_SERVER': {6: 1, 31: 2, "else": 3},
+
+ 'HIVE_SERVER': {6: 1, 31: 2, "else": 4},
+ 'HIVE_METASTORE': {6: 1, 31: 2, "else": 4},
+ 'WEBHCAT_SERVER': {6: 1, 31: 2, "else": 4},
+ }.get(componentName, None)
+
+ def isNotPreferableOnAmbariServerHost(self, component):
+ componentName = component["StackServiceComponents"]["component_name"]
+ service = ['GANGLIA_SERVER', 'NAGIOS_SERVER']
+ return componentName in service
+
+ def validateComponentLayout(self, services, hosts):
+ """Returns array of Validation objects about issues with hostnames components assigned to"""
+ stackName = services["Versions"]["stack_name"]
+ stackVersion = services["Versions"]["stack_version"]
+
+ validations = {
+ "Versions": {"stack_name": stackName, "stack_version": stackVersion},
+ "items": [ ]
+ }
+ items = validations["items"]
+
+ # Validating NAMENODE and SECONDARY_NAMENODE are on different hosts if possible
+ hostsList = [host["Hosts"]["host_name"] for host in hosts["items"]]
+ hostsCount = len(hostsList)
+ servicesList = [service["StackServices"]["service_name"] for service in services["services"]]
+
+ componentsListList = [service["components"] for service in services["services"]]
+ componentsList = [item for sublist in componentsListList for item in sublist]
+ nameNodeHosts = [component["StackServiceComponents"]["hostnames"] for component in componentsList if component["StackServiceComponents"]["component_name"] == "NAMENODE"]
+ secondaryNameNodeHosts = [component["StackServiceComponents"]["hostnames"] for component in componentsList if component["StackServiceComponents"]["component_name"] == "SECONDARY_NAMENODE"]
+
+ if hostsCount > 1 and len(nameNodeHosts) > 0 and len(secondaryNameNodeHosts) > 0:
+ nameNodeHosts = nameNodeHosts[0]
+ secondaryNameNodeHosts = secondaryNameNodeHosts[0]
+ commonHosts = list(set(nameNodeHosts).intersection(secondaryNameNodeHosts))
+ for host in commonHosts:
+ items.append( { "type": 'host-component', "level": 'WARN', "message": 'NameNode and Secondary NameNode cannot be hosted on same machine', "component-name": 'NAMENODE', "host": str(host) } )
+ items.append( { "type": 'host-component', "level": 'WARN', "message": 'NameNode and Secondary NameNode cannot be hosted on same machine', "component-name": 'SECONDARY_NAMENODE', "host": str(host) } )
+
+ # Validating cardinality
+ for component in componentsList:
+ if component["StackServiceComponents"]["cardinality"] is not None:
+ componentName = component["StackServiceComponents"]["component_name"]
+ componentHostsCount = 0
+ if component["StackServiceComponents"]["hostnames"] is not None:
+ componentHostsCount = len(component["StackServiceComponents"]["hostnames"])
+ cardinality = str(component["StackServiceComponents"]["cardinality"])
+ # cardinality types: null, 1+, 1-2, 1, ALL
+ hostsMax = -sys.maxint - 1
+ hostsMin = sys.maxint
+ hostsMin = 0
+ hostsMax = 0
+ if "+" in cardinality:
+ hostsMin = int(cardinality[:-1])
+ hostsMax = sys.maxint
+ elif "-" in cardinality:
+ nums = cardinality.split("-")
+ hostsMin = int(nums[0])
+ hostsMax = int(nums[1])
+ elif "ALL" == cardinality:
+ hostsMin = hostsCount
+ hostsMax = hostsCount
+ else:
+ hostsMin = int(cardinality)
+ hostsMax = int(cardinality)
+
+ if componentHostsCount > hostsMax or componentHostsCount < hostsMin:
+ items.append( { "type": 'host-component', "level": 'ERROR', "message": 'Cardinality violation, cardinality={0}, hosts count={1}'.format(cardinality, str(componentHostsCount)), "component-name": str(componentName) } )
+
+ # Validating host-usage
+ usedHostsListList = [component["StackServiceComponents"]["hostnames"] for component in componentsList if not self.isNotValuable(component)]
+ usedHostsList = [item for sublist in usedHostsListList for item in sublist]
+ nonUsedHostsList = [item for item in hostsList if item not in usedHostsList]
+ for host in nonUsedHostsList:
+ items.append( { "type": 'host-component', "level": 'ERROR', "message": 'Host is not used', "host": str(host) } )
+
+ return validations
+ pass
+
+ def isNotValuable(self, component):
+ componentName = component["StackServiceComponents"]["component_name"]
+ service = ['JOURNALNODE', 'ZKFC', 'GANGLIA_MONITOR']
+ return componentName in service
+
+ def recommendConfigurations(self, services, hosts):
+ stackName = services["Versions"]["stack_name"]
+ stackVersion = services["Versions"]["stack_version"]
+ hostsList = [host["Hosts"]["host_name"] for host in hosts["items"]]
+ servicesList = [service["StackServices"]["service_name"] for service in services["services"]]
+ components = [component["StackServiceComponents"]["component_name"]
+ for service in services["services"]
+ for component in service["components"]]
+
+ clusterData = self.getClusterData(servicesList, hosts, components)
+
+ recommendations = {
+ "Versions": {"stack_name": stackName, "stack_version": stackVersion},
+ "hosts": hostsList,
+ "services": servicesList,
+ "recommendations": {
+ "blueprint": {
+ "configurations": {},
+ "host_groups": []
+ },
+ "blueprint_cluster_binding": {
+ "host_groups": []
+ }
+ }
+ }
+
+ configurations = recommendations["recommendations"]["blueprint"]["configurations"]
+
+ for service in servicesList:
+ calculation = self.recommendServiceConfigurations(service)
+ if calculation is not None:
+ calculation(configurations, clusterData)
+
+ return recommendations
+
+ def recommendServiceConfigurations(self, service):
+ return {
+ }.get(service, None)
+
+ def putProperty(self, config, configType):
+ config[configType] = {"properties": {}}
+ def appendProperty(key, value):
+ config[configType]["properties"][key] = str(value)
+ return appendProperty
+
+ def getClusterData(self, servicesList, hosts, components):
+
+ hBaseInstalled = False
+ if 'HBASE' in servicesList:
+ hBaseInstalled = True
+
+ cluster = {
+ "cpu": 0,
+ "disk": 0,
+ "ram": 0,
+ "hBaseInstalled": hBaseInstalled,
+ "components": components
+ }
+
+ if len(hosts["items"]) > 0:
+ host = hosts["items"][0]["Hosts"]
+ cluster["cpu"] = host["cpu_count"]
+ cluster["disk"] = len(host["disk_info"])
+ cluster["ram"] = int(host["total_mem"] / (1024 * 1024))
+
+ ramRecommendations = [
+ {"os":1, "hbase":1},
+ {"os":2, "hbase":1},
+ {"os":2, "hbase":2},
+ {"os":4, "hbase":4},
+ {"os":6, "hbase":8},
+ {"os":8, "hbase":8},
+ {"os":8, "hbase":8},
+ {"os":12, "hbase":16},
+ {"os":24, "hbase":24},
+ {"os":32, "hbase":32},
+ {"os":64, "hbase":64}
+ ]
+ index = {
+ cluster["ram"] <= 4: 0,
+ 4 < cluster["ram"] <= 8: 1,
+ 8 < cluster["ram"] <= 16: 2,
+ 16 < cluster["ram"] <= 24: 3,
+ 24 < cluster["ram"] <= 48: 4,
+ 48 < cluster["ram"] <= 64: 5,
+ 64 < cluster["ram"] <= 72: 6,
+ 72 < cluster["ram"] <= 96: 7,
+ 96 < cluster["ram"] <= 128: 8,
+ 128 < cluster["ram"] <= 256: 9,
+ 256 < cluster["ram"]: 10
+ }[1]
+ cluster["reservedRam"] = ramRecommendations[index]["os"]
+ cluster["hbaseRam"] = ramRecommendations[index]["hbase"]
+
+ cluster["minContainerSize"] = {
+ cluster["ram"] <= 4: 256,
+ 4 < cluster["ram"] <= 8: 512,
+ 8 < cluster["ram"] <= 24: 1024,
+ 24 < cluster["ram"]: 2048
+ }[1]
+
+ '''containers = max(3, min (2*cores,min (1.8*DISKS,(Total available RAM) / MIN_CONTAINER_SIZE))))'''
+ cluster["containers"] = max(3,
+ min(2 * cluster["cpu"],
+ int(min(1.8 * cluster["disk"],
+ cluster["ram"] / cluster["minContainerSize"]))))
+
+ '''ramPerContainers = max(2GB, RAM - reservedRam - hBaseRam) / containers'''
+ cluster["ramPerContainer"] = max(2048,
+ cluster["ram"] - cluster["reservedRam"] - cluster["hbaseRam"])
+ cluster["ramPerContainer"] /= cluster["containers"]
+ '''If greater than 1GB, value will be in multiples of 512.'''
+ if cluster["ramPerContainer"] > 1024:
+ cluster["ramPerContainer"] = ceil(cluster["ramPerContainer"] / 512) * 512
+
+ cluster["mapMemory"] = int(cluster["ramPerContainer"])
+ cluster["reduceMemory"] = cluster["ramPerContainer"]
+ cluster["amMemory"] = max(cluster["mapMemory"], cluster["reduceMemory"])
+
+ return cluster
+
+
+ def validateConfigurations(self, services, hosts):
+ """Returns array of Validation objects about issues with configuration values provided in services"""
+ stackName = services["Versions"]["stack_name"]
+ stackVersion = services["Versions"]["stack_version"]
+
+ validations = {
+ "Versions": {"stack_name": stackName, "stack_version": stackVersion},
+ "items": [ ]
+ }
+ items = validations["items"]
+
+ recommendations = self.recommendConfigurations(services, hosts)
+ recommendedDefaults = recommendations["recommendations"]["blueprint"]["configurations"]
+
+ configurations = services["configurations"]
+ for service in services["services"]:
+ serviceName = service["StackServices"]["service_name"]
+ validator = self.validateServiceConfigurations(serviceName)
+ if validator is not None:
+ siteName = validator[0]
+ method = validator[1]
+ if siteName in recommendedDefaults:
+ siteProperties = getSiteProperties(configurations, siteName)
+ if siteProperties is not None:
+ resultItems = method(siteProperties, recommendedDefaults[siteName]["properties"])
+ items.extend(resultItems)
+ return validations
+ pass
+
+ def validateServiceConfigurations(self, serviceName):
+ return {
+ }.get(serviceName, None)
+
+ def toConfigurationValidationErrors(self, items, siteName):
+ result = []
+ for item in items:
+ if item["message"] is not None:
+ error = { "type": 'configuration', "level": 'ERROR', "message": item["message"], "config-type": siteName, "config-name": item["config-name"] }
+ result.append(error)
+ return result
+
+ def validatorLessThenDefaultValue(self, properties, recommendedDefaults, propertyName):
+ if not propertyName in properties:
+ return "Value should be set"
+ value = to_number(properties[propertyName])
+ if value is None:
+ return "Value should be integer"
+ defaultValue = to_number(recommendedDefaults[propertyName])
+ if defaultValue is None:
+ return None
+ if value < defaultValue:
+ return "Value is less than the recommended default of {0}".format(defaultValue)
+ return None
+
+ def validateXmxValue(self, properties, recommendedDefaults, propertyName):
+ if not propertyName in properties:
+ return "Value should be set"
+ value = properties[propertyName]
+ defaultValue = recommendedDefaults[propertyName]
+ if defaultValue is None:
+ return "Config's default value can't be null or undefined"
+ if not checkXmxValueFormat(value):
+ return 'Invalid value format'
+ valueInt = formatXmxSizeToBytes(getXmxSize(value))
+ defaultValueXmx = getXmxSize(defaultValue)
+ defaultValueInt = formatXmxSizeToBytes(defaultValueXmx)
+ if valueInt < defaultValueInt:
+ return "Value is less than the recommended default of -Xmx" + defaultValueXmx
+ return None
+
+
+# Validation helper methods
+def getSiteProperties(configurations, siteName):
+ siteConfig = configurations.get(siteName)
+ if siteConfig is None:
+ return None
+ return siteConfig.get("properties")
+
+def to_number(s):
+ try:
+ return int(re.sub("\D", "", s))
+ except ValueError:
+ return None
+
+def checkXmxValueFormat(value):
+ p = re.compile('-Xmx(\d+)(b|k|m|g|p|t|B|K|M|G|P|T)?')
+ matches = p.findall(value)
+ return len(matches) == 1
+
+def getXmxSize(value):
+ p = re.compile("-Xmx(\d+)(.?)")
+ result = p.findall(value)[0]
+ if len(result) > 1:
+ # result[1] - is a space or size formatter (b|k|m|g etc)
+ return result[0] + result[1].lower()
+ return result[0]
+
+def formatXmxSizeToBytes(value):
+ value = value.lower()
+ if len(value) == 0:
+ return 0
+ modifier = value[-1]
+
+ if modifier == ' ' or modifier in "0123456789":
+ modifier = 'b'
+ m = {
+ modifier == 'b': 1,
+ modifier == 'k': 1024,
+ modifier == 'm': 1024 * 1024,
+ modifier == 'g': 1024 * 1024 * 1024,
+ modifier == 't': 1024 * 1024 * 1024 * 1024,
+ modifier == 'p': 1024 * 1024 * 1024 * 1024 * 1024
+ }[1]
+ return to_number(value) * m
+
+
+# Recommendation helper methods
+def isAlreadyPopulated(component):
+ if component["StackServiceComponents"]["hostnames"] is not None:
+ return len(component["StackServiceComponents"]["hostnames"]) > 0
+ return False
+
+def isClient(component):
+ return component["StackServiceComponents"]["component_category"] == 'CLIENT'
+
+def isSlave(component):
+ componentName = component["StackServiceComponents"]["component_name"]
+ isSlave = component["StackServiceComponents"]["component_category"] == 'SLAVE'
+ return isSlave
+
+def isMaster(component):
+ componentName = component["StackServiceComponents"]["component_name"]
+ isMaster = component["StackServiceComponents"]["is_master"]
+ return isMaster
+
+def isLocalHost(hostName):
+ return socket.getfqdn(hostName) == socket.getfqdn()
+
+def isMasterWithMultipleInstances(component):
+ componentName = component["StackServiceComponents"]["component_name"]
+ masters = ['ZOOKEEPER_SERVER', 'HBASE_MASTER']
+ return componentName in masters
+
+def defaultNoOfMasterHosts(component):
+ componentName = component["StackServiceComponents"]["component_name"]
+ return cardinality(componentName)[min]
+
+
+# Helper dictionaries
+def cardinality(componentName):
+ return {
+ 'ZOOKEEPER_SERVER': {min: 3},
+ 'HBASE_MASTER': {min: 1},
+ }.get(componentName, {min:1, max:1})
+
http://git-wip-us.apache.org/repos/asf/ambari/blob/fb1e0ca5/ambari-server/src/main/resources/stacks/HDP/1.3.3/services/stack_advisor.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/1.3.3/services/stack_advisor.py b/ambari-server/src/main/resources/stacks/HDP/1.3.3/services/stack_advisor.py
new file mode 100644
index 0000000..f91efd8
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/1.3.3/services/stack_advisor.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env ambari-python-wrap
+"""
+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
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+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.
+"""
+
+import socket
+
+from stack_advisor import StackAdvisor
+
+class HDP133StackAdvisor(HDP132StackAdvisor):
+ pass
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/fb1e0ca5/ambari-server/src/main/resources/stacks/HDP/1.3/services/stack_advisor.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/1.3/services/stack_advisor.py b/ambari-server/src/main/resources/stacks/HDP/1.3/services/stack_advisor.py
new file mode 100644
index 0000000..998ecaa
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/1.3/services/stack_advisor.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env ambari-python-wrap
+"""
+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
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+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.
+"""
+
+import socket
+
+from stack_advisor import StackAdvisor
+
+class HDP13StackAdvisor(HDP133StackAdvisor):
+ pass
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/fb1e0ca5/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
index 53a78eb..37d1af4 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/AmbariMetaInfoTest.java
@@ -435,6 +435,15 @@ public class AmbariMetaInfoTest {
}
@Test
+ public void testGetStackParentVersions() throws Exception {
+ List<String> parents = metaInfo.getStackParentVersions(STACK_NAME_HDP, "2.0.8");
+ Assert.assertEquals(3, parents.size());
+ Assert.assertEquals("2.0.7", parents.get(0));
+ Assert.assertEquals("2.0.6", parents.get(1));
+ Assert.assertEquals("2.0.5", parents.get(2));
+ }
+
+ @Test
public void testGetProperties() throws Exception {
Set<PropertyInfo> properties = metaInfo.getProperties(STACK_NAME_HDP, STACK_VERSION_HDP, SERVICE_NAME_HDFS);
Assert.assertEquals(properties.size(), PROPERTIES_CNT);
http://git-wip-us.apache.org/repos/asf/ambari/blob/fb1e0ca5/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelperTest.java
index e4cf97a..87729b1 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelperTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorHelperTest.java
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.when;
import java.io.IOException;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest.StackAdvisorRequestBuilder;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest.StackAdvisorRequestType;
import org.apache.ambari.server.api.services.stackadvisor.commands.GetComponentLayoutRecommnedationCommand;
@@ -48,7 +49,8 @@ public class StackAdvisorHelperTest {
public void testValidate_returnsCommandResult() throws StackAdvisorException, IOException {
Configuration configuration = mock(Configuration.class);
StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class);
- StackAdvisorHelper helper = spy(new StackAdvisorHelper(configuration, saRunner));
+ AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class);
+ StackAdvisorHelper helper = spy(new StackAdvisorHelper(configuration, saRunner, metaInfo));
StackAdvisorCommand<ValidationResponse> command = mock(StackAdvisorCommand.class);
ValidationResponse expected = mock(ValidationResponse.class);
@@ -69,7 +71,8 @@ public class StackAdvisorHelperTest {
IOException {
Configuration configuration = mock(Configuration.class);
StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class);
- StackAdvisorHelper helper = spy(new StackAdvisorHelper(configuration, saRunner));
+ AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class);
+ StackAdvisorHelper helper = spy(new StackAdvisorHelper(configuration, saRunner, metaInfo));
StackAdvisorCommand<ValidationResponse> command = mock(StackAdvisorCommand.class);
StackAdvisorRequestType requestType = StackAdvisorRequestType.HOST_GROUPS;
@@ -88,7 +91,8 @@ public class StackAdvisorHelperTest {
public void testRecommend_returnsCommandResult() throws StackAdvisorException, IOException {
Configuration configuration = mock(Configuration.class);
StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class);
- StackAdvisorHelper helper = spy(new StackAdvisorHelper(configuration, saRunner));
+ AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class);
+ StackAdvisorHelper helper = spy(new StackAdvisorHelper(configuration, saRunner, metaInfo));
StackAdvisorCommand<RecommendationResponse> command = mock(StackAdvisorCommand.class);
RecommendationResponse expected = mock(RecommendationResponse.class);
@@ -109,7 +113,8 @@ public class StackAdvisorHelperTest {
IOException {
Configuration configuration = mock(Configuration.class);
StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class);
- StackAdvisorHelper helper = spy(new StackAdvisorHelper(configuration, saRunner));
+ AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class);
+ StackAdvisorHelper helper = spy(new StackAdvisorHelper(configuration, saRunner, metaInfo));
StackAdvisorCommand<RecommendationResponse> command = mock(StackAdvisorCommand.class);
StackAdvisorRequestType requestType = StackAdvisorRequestType.HOST_GROUPS;
@@ -128,7 +133,8 @@ public class StackAdvisorHelperTest {
throws IOException, StackAdvisorException {
Configuration configuration = mock(Configuration.class);
StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class);
- StackAdvisorHelper helper = new StackAdvisorHelper(configuration, saRunner);
+ AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class);
+ StackAdvisorHelper helper = new StackAdvisorHelper(configuration, saRunner, metaInfo);
StackAdvisorRequestType requestType = StackAdvisorRequestType.HOST_GROUPS;
StackAdvisorCommand<RecommendationResponse> command = helper
@@ -142,7 +148,8 @@ public class StackAdvisorHelperTest {
throws IOException, StackAdvisorException {
Configuration configuration = mock(Configuration.class);
StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class);
- StackAdvisorHelper helper = new StackAdvisorHelper(configuration, saRunner);
+ AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class);
+ StackAdvisorHelper helper = new StackAdvisorHelper(configuration, saRunner, metaInfo);
StackAdvisorRequestType requestType = StackAdvisorRequestType.HOST_GROUPS;
StackAdvisorCommand<ValidationResponse> command = helper.createValidationCommand(requestType);
@@ -155,7 +162,8 @@ public class StackAdvisorHelperTest {
throws IOException, StackAdvisorException {
Configuration configuration = mock(Configuration.class);
StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class);
- StackAdvisorHelper helper = new StackAdvisorHelper(configuration, saRunner);
+ AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class);
+ StackAdvisorHelper helper = new StackAdvisorHelper(configuration, saRunner, metaInfo);
StackAdvisorRequestType requestType = StackAdvisorRequestType.CONFIGURATIONS;
StackAdvisorCommand<ValidationResponse> command = helper.createValidationCommand(requestType);
http://git-wip-us.apache.org/repos/asf/ambari/blob/fb1e0ca5/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandTest.java
index 5e4e3d0..cf792ff 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandTest.java
@@ -19,8 +19,10 @@
package org.apache.ambari.server.api.services.stackadvisor.commands;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
@@ -29,16 +31,23 @@ import static org.mockito.Mockito.when;
import java.io.File;
import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
import javax.ws.rs.WebApplicationException;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest.StackAdvisorRequestBuilder;
import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRunner;
import org.apache.ambari.server.api.services.stackadvisor.commands.StackAdvisorCommand.StackAdvisorData;
import org.apache.commons.io.FileUtils;
+import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.node.ArrayNode;
+import org.codehaus.jackson.node.ObjectNode;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -68,8 +77,10 @@ public class StackAdvisorCommandTest {
String stackAdvisorScript = "echo";
int requestId = 0;
StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class);
+ AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class);
+ doReturn(Collections.emptyList()).when(metaInfo).getStackParentVersions(anyString(), anyString());
StackAdvisorCommand<TestResource> command = spy(new TestStackAdvisorCommand(recommendationsDir,
- stackAdvisorScript, requestId, saRunner));
+ stackAdvisorScript, requestId, saRunner, metaInfo));
StackAdvisorRequest request = StackAdvisorRequestBuilder.forStack("stackName", "stackVersion")
.build();
@@ -86,8 +97,10 @@ public class StackAdvisorCommandTest {
String stackAdvisorScript = "echo";
int requestId = 0;
StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class);
+ AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class);
+ doReturn(Collections.emptyList()).when(metaInfo).getStackParentVersions(anyString(), anyString());
StackAdvisorCommand<TestResource> command = spy(new TestStackAdvisorCommand(recommendationsDir,
- stackAdvisorScript, requestId, saRunner));
+ stackAdvisorScript, requestId, saRunner, metaInfo));
StackAdvisorRequest request = StackAdvisorRequestBuilder.forStack("stackName", "stackVersion")
.build();
@@ -112,8 +125,10 @@ public class StackAdvisorCommandTest {
String stackAdvisorScript = "echo";
int requestId = 0;
StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class);
+ AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class);
+ doReturn(Collections.emptyList()).when(metaInfo).getStackParentVersions(anyString(), anyString());
StackAdvisorCommand<TestResource> command = spy(new TestStackAdvisorCommand(recommendationsDir,
- stackAdvisorScript, requestId, saRunner));
+ stackAdvisorScript, requestId, saRunner, metaInfo));
StackAdvisorRequest request = StackAdvisorRequestBuilder.forStack("stackName", "stackVersion")
.build();
@@ -137,8 +152,10 @@ public class StackAdvisorCommandTest {
String stackAdvisorScript = "echo";
final int requestId = 0;
StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class);
+ AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class);
+ doReturn(Collections.emptyList()).when(metaInfo).getStackParentVersions(anyString(), anyString());
final StackAdvisorCommand<TestResource> command = spy(new TestStackAdvisorCommand(
- recommendationsDir, stackAdvisorScript, requestId, saRunner));
+ recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo));
StackAdvisorRequest request = StackAdvisorRequestBuilder.forStack("stackName", "stackVersion")
.build();
@@ -165,10 +182,61 @@ public class StackAdvisorCommandTest {
assertEquals(expected, result.getType());
}
+ @Test
+ public void testPopulateStackHierarchy() throws Exception {
+ File file = mock(File.class);
+ StackAdvisorRunner stackAdvisorRunner = mock(StackAdvisorRunner.class);
+ AmbariMetaInfo ambariMetaInfo = mock(AmbariMetaInfo.class);
+ StackAdvisorCommand<TestResource> cmd = new TestStackAdvisorCommand(file, "test", 1,
+ stackAdvisorRunner, ambariMetaInfo);
+ ObjectNode objectNode = (ObjectNode) cmd.mapper.readTree("{\"Versions\": " +
+ "{\"stack_name\": \"stack\", \"stack_version\":\"1.0.0\"}}");
+
+ doReturn(Arrays.asList("0.9", "0.8")).when(ambariMetaInfo).getStackParentVersions("stack", "1.0.0");
+
+ cmd.populateStackHierarchy(objectNode);
+
+ JsonNode stackHierarchy = objectNode.get("Versions").get("stack_hierarchy");
+ assertNotNull(stackHierarchy);
+ JsonNode stackName = stackHierarchy.get("stack_name");
+ assertNotNull(stackName);
+ assertEquals("stack", stackName.asText());
+ ArrayNode stackVersions = (ArrayNode) stackHierarchy.get("stack_versions");
+ assertNotNull(stackVersions);
+ assertEquals(2, stackVersions.size());
+ Iterator<JsonNode> stackVersionsElements = stackVersions.getElements();
+ assertEquals("0.9", stackVersionsElements.next().asText());
+ assertEquals("0.8", stackVersionsElements.next().asText());
+ }
+
+ @Test
+ public void testPopulateStackHierarchy_noParents() throws Exception {
+ File file = mock(File.class);
+ StackAdvisorRunner stackAdvisorRunner = mock(StackAdvisorRunner.class);
+ AmbariMetaInfo ambariMetaInfo = mock(AmbariMetaInfo.class);
+ StackAdvisorCommand<TestResource> cmd = new TestStackAdvisorCommand(file, "test", 1,
+ stackAdvisorRunner, ambariMetaInfo);
+ ObjectNode objectNode = (ObjectNode) cmd.mapper.readTree("{\"Versions\": " +
+ "{\"stack_name\": \"stack\", \"stack_version\":\"1.0.0\"}}");
+
+ doReturn(Collections.emptyList()).when(ambariMetaInfo).getStackParentVersions("stack", "1.0.0");
+
+ cmd.populateStackHierarchy(objectNode);
+
+ JsonNode stackHierarchy = objectNode.get("Versions").get("stack_hierarchy");
+ assertNotNull(stackHierarchy);
+ JsonNode stackName = stackHierarchy.get("stack_name");
+ assertNotNull(stackName);
+ assertEquals("stack", stackName.asText());
+ ArrayNode stackVersions = (ArrayNode) stackHierarchy.get("stack_versions");
+ assertNotNull(stackVersions);
+ assertEquals(0, stackVersions.size());
+ }
+
class TestStackAdvisorCommand extends StackAdvisorCommand<TestResource> {
public TestStackAdvisorCommand(File recommendationsDir, String stackAdvisorScript,
- int requestId, StackAdvisorRunner saRunner) {
- super(recommendationsDir, stackAdvisorScript, requestId, saRunner);
+ int requestId, StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) {
+ super(recommendationsDir, stackAdvisorScript, requestId, saRunner, metaInfo);
}
@Override