AMBARI-21530 - Service Checks During Upgrades Should Use Desired Stack (jonathanhurley)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/e87a3e31 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/e87a3e31 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/e87a3e31 Branch: refs/heads/branch-feature-AMBARI-14714 Commit: e87a3e31a9a18c5178f1170cef15c4de47f6808e Parents: 9c45110 Author: Jonathan Hurley <jhur...@hortonworks.com> Authored: Wed Jul 19 22:04:07 2017 -0400 Committer: Jonathan Hurley <jhur...@hortonworks.com> Committed: Thu Jul 20 17:15:21 2017 -0400 ---------------------------------------------------------------------- .../actionmanager/ExecutionCommandWrapper.java | 34 +++++++- .../AmbariCustomCommandExecutionHelper.java | 7 +- .../AmbariManagementControllerImpl.java | 7 +- .../internal/UpgradeResourceProvider.java | 91 +++++++++++++++----- .../2.1.0.2.0/package/scripts/historyserver.py | 2 +- .../2.1.0.2.0/package/scripts/params_linux.py | 11 ++- .../2.1.0.2.0/package/scripts/service_check.py | 6 +- .../src/test/python/TestStackFeature.py | 61 +++++++++++++ 8 files changed, 174 insertions(+), 45 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/e87a3e31/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java index efd609a..91db7d0 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ExecutionCommandWrapper.java @@ -17,6 +17,9 @@ */ package org.apache.ambari.server.actionmanager; +import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOOKS_FOLDER; +import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_PACKAGE_FOLDER; + import java.util.HashMap; import java.util.Map; import java.util.TreeMap; @@ -27,6 +30,7 @@ import org.apache.ambari.server.ServiceNotFoundException; import org.apache.ambari.server.agent.AgentCommand.AgentCommandType; import org.apache.ambari.server.agent.ExecutionCommand; import org.apache.ambari.server.agent.ExecutionCommand.KeyNames; +import org.apache.ambari.server.api.services.AmbariMetaInfo; import org.apache.ambari.server.orm.dao.HostRoleCommandDAO; import org.apache.ambari.server.orm.entities.RepositoryVersionEntity; import org.apache.ambari.server.state.Cluster; @@ -35,6 +39,9 @@ import org.apache.ambari.server.state.ConfigHelper; import org.apache.ambari.server.state.DesiredConfig; import org.apache.ambari.server.state.Service; import org.apache.ambari.server.state.ServiceComponent; +import org.apache.ambari.server.state.ServiceInfo; +import org.apache.ambari.server.state.StackId; +import org.apache.ambari.server.state.StackInfo; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; @@ -63,6 +70,12 @@ public class ExecutionCommandWrapper { @Inject private Gson gson; + /** + * Used for injecting hooks and common-services into the command. + */ + @Inject + private AmbariMetaInfo ambariMetaInfo; + @AssistedInject public ExecutionCommandWrapper(@Assisted String jsonExecutionCommand) { this.jsonExecutionCommand = jsonExecutionCommand; @@ -208,9 +221,28 @@ public class ExecutionCommandWrapper { } } + Map<String, String> commandParams = executionCommand.getCommandParams(); + if (null != repositoryVersion) { - executionCommand.getCommandParams().put(KeyNames.VERSION, repositoryVersion.getVersion()); + commandParams.put(KeyNames.VERSION, repositoryVersion.getVersion()); executionCommand.getHostLevelParams().put(KeyNames.CURRENT_VERSION, repositoryVersion.getVersion()); + + StackId stackId = repositoryVersion.getStackId(); + StackInfo stackInfo = ambariMetaInfo.getStack(stackId.getStackName(), + stackId.getStackVersion()); + + if (!commandParams.containsKey(HOOKS_FOLDER)) { + commandParams.put(HOOKS_FOLDER, stackInfo.getStackHooksFolder()); + } + + if (!commandParams.containsKey(SERVICE_PACKAGE_FOLDER)) { + if (!StringUtils.isEmpty(serviceName)) { + ServiceInfo serviceInfo = ambariMetaInfo.getService(stackId.getStackName(), + stackId.getStackVersion(), serviceName); + + commandParams.put(SERVICE_PACKAGE_FOLDER, serviceInfo.getServicePackageFolder()); + } + } } } catch (ServiceNotFoundException serviceNotFoundException) { // it's possible that there are commands specified for a service where http://git-wip-us.apache.org/repos/asf/ambari/blob/e87a3e31/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java index 5180870..0b140e4 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java @@ -27,7 +27,6 @@ import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.CUSTOM_CO import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_DRIVER_FILENAME; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_NAME; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.GROUP_LIST; -import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOOKS_FOLDER; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOST_SYS_PREPPED; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_LOCATION; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.MYSQL_JDBC_URL; @@ -36,7 +35,6 @@ import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.ORACLE_JD import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.REPO_INFO; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT_TYPE; -import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_PACKAGE_FOLDER; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_NAME; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_VERSION; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.USER_GROUPS; @@ -492,8 +490,6 @@ public class AmbariCustomCommandExecutionHelper { } commandParams.put(COMMAND_TIMEOUT, "" + commandTimeout); - commandParams.put(SERVICE_PACKAGE_FOLDER, serviceInfo.getServicePackageFolder()); - commandParams.put(HOOKS_FOLDER, stackInfo.getStackHooksFolder()); Map<String, String> roleParams = execCmd.getRoleParams(); if (roleParams == null) { @@ -811,8 +807,7 @@ public class AmbariCustomCommandExecutionHelper { actualTimeout = actualTimeout < MIN_STRICT_SERVICE_CHECK_TIMEOUT ? MIN_STRICT_SERVICE_CHECK_TIMEOUT : actualTimeout; commandParams.put(COMMAND_TIMEOUT, Integer.toString(actualTimeout)); } - commandParams.put(SERVICE_PACKAGE_FOLDER, serviceInfo.getServicePackageFolder()); - commandParams.put(HOOKS_FOLDER, stackInfo.getStackHooksFolder()); + StageUtils.useAmbariJdkInCommandParams(commandParams, configs); execCmd.setCommandParams(commandParams); http://git-wip-us.apache.org/repos/asf/ambari/blob/e87a3e31/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java index 4229d34..44943c7 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java @@ -28,7 +28,6 @@ import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.COMMAND_T import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.CUSTOM_FOLDER; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_DRIVER_FILENAME; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.GROUP_LIST; -import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOOKS_FOLDER; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.MAX_DURATION_OF_RETRIES; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.NOT_MANAGED_HDFS_PATH_LIST; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.PACKAGE_LIST; @@ -36,7 +35,6 @@ import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.PACKAGE_V import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.REPO_INFO; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT_TYPE; -import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_PACKAGE_FOLDER; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_REPO_INFO; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.UNLIMITED_KEY_JCE_REQUIRED; import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.USER_GROUPS; @@ -1536,7 +1534,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle Map.Entry<String, String> pair = (Map.Entry) it.next(); // Check the value if both keys exist if (newConfigValues.containsKey(pair.getKey())) { - if (!newConfigValues.get((String) pair.getKey()).equals(pair.getValue())) { + if (!newConfigValues.get(pair.getKey()).equals(pair.getValue())) { configsChanged.put(pair.getKey(), "changed"); } } else { @@ -2459,9 +2457,6 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle } commandParams.put(COMMAND_TIMEOUT, actualTimeout); - commandParams.put(SERVICE_PACKAGE_FOLDER, - serviceInfo.getServicePackageFolder()); - commandParams.put(HOOKS_FOLDER, stackInfo.getStackHooksFolder()); String customCacheDirectory = componentInfo.getCustomFolder(); if (customCacheDirectory != null) { http://git-wip-us.apache.org/repos/asf/ambari/blob/e87a3e31/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java index 22858dd..e8cd220 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UpgradeResourceProvider.java @@ -856,6 +856,63 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider } } + /** + * Adds the hooks and service folders based on the effective stack ID and the + * name of the service from the wrapper. + * + * @param wrapper + * the stage wrapper to use when detemrining the service name. + * @param effectiveStackId + * the stack ID to use when getting the hooks and service folders. + * @param commandParams + * the params to update with the new values + * @throws AmbariException + */ + private void applyRepositoryAssociatedParameters(StageWrapper wrapper, StackId effectiveStackId, + Map<String, String> commandParams) throws AmbariException { + if (CollectionUtils.isNotEmpty(wrapper.getTasks()) + && wrapper.getTasks().get(0).getService() != null) { + + AmbariMetaInfo ambariMetaInfo = s_metaProvider.get(); + + StackInfo stackInfo = ambariMetaInfo.getStack(effectiveStackId.getStackName(), + effectiveStackId.getStackVersion()); + + String serviceName = wrapper.getTasks().get(0).getService(); + ServiceInfo serviceInfo = ambariMetaInfo.getService(effectiveStackId.getStackName(), + effectiveStackId.getStackVersion(), serviceName); + + commandParams.put(SERVICE_PACKAGE_FOLDER, serviceInfo.getServicePackageFolder()); + commandParams.put(HOOKS_FOLDER, stackInfo.getStackHooksFolder()); + } + } + + /** + * Creates an action stage using the {@link #EXECUTE_TASK_ROLE} custom action + * to execute some Python command. + * + * @param context + * the upgrade context. + * @param request + * the request object to add the stage to. + * @param effectiveRepositoryVersion + * the stack/version to use when generating content for the command. + * On some upgrade types, this may change during the course of the + * upgrade orchestration. An express upgrade changes this after + * stopping all services. + * @param entity + * the upgrade entity to set the stage information on + * @param wrapper + * the stage wrapper containing information to generate the stage. + * @param skippable + * {@code true} to mark the stage as being skippable if a failure + * occurs. + * @param supportsAutoSkipOnFailure + * {@code true} to automatically skip on a failure. + * @param allowRetry + * {@code true} to be able to retry the failed stage. + * @throws AmbariException + */ private void makeActionStage(UpgradeContext context, RequestStageContainer request, RepositoryVersionEntity effectiveRepositoryVersion, UpgradeItemEntity entity, StageWrapper wrapper, boolean skippable, boolean supportsAutoSkipOnFailure, @@ -869,38 +926,28 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider Cluster cluster = context.getCluster(); LOG.debug("Analyzing upgrade item {} with tasks: {}.", entity.getText(), entity.getTasks()); - Map<String, String> params = getNewParameterMap(request, context); - params.put(UpgradeContext.COMMAND_PARAM_TASKS, entity.getTasks()); - - // Apply additional parameters to the command that come from the stage. - applyAdditionalParameters(wrapper, params); - - // Because custom task may end up calling a script/function inside a - // service, it is necessary to set the - // service_package_folder and hooks_folder params. - AmbariMetaInfo ambariMetaInfo = s_metaProvider.get(); - StackId stackId = effectiveRepositoryVersion.getStackId(); - - StackInfo stackInfo = ambariMetaInfo.getStack(stackId.getStackName(), - stackId.getStackVersion()); // if the service/component are specified, then make sure to grab them off // of the wrapper so they can be stored on the command for use later String serviceName = null; String componentName = null; - if (wrapper.getTasks() != null && wrapper.getTasks().size() > 0 && wrapper.getTasks().get(0).getService() != null) { TaskWrapper taskWrapper = wrapper.getTasks().get(0); serviceName = taskWrapper.getService(); componentName = taskWrapper.getComponent(); + } - ServiceInfo serviceInfo = ambariMetaInfo.getService(stackId.getStackName(), - stackId.getStackVersion(), serviceName); + Map<String, String> params = getNewParameterMap(request, context); + params.put(UpgradeContext.COMMAND_PARAM_TASKS, entity.getTasks()); - params.put(SERVICE_PACKAGE_FOLDER, serviceInfo.getServicePackageFolder()); - params.put(HOOKS_FOLDER, stackInfo.getStackHooksFolder()); - } + // Apply additional parameters to the command that come from the stage. + applyAdditionalParameters(wrapper, params); + + // the ru_execute_tasks invokes scripts - it needs information about where + // the scripts live and for that it should always use the target repository + // stack + applyRepositoryAssociatedParameters(wrapper, effectiveRepositoryVersion.getStackId(), params); // add each host to this stage RequestResourceFilter filter = new RequestResourceFilter(serviceName, componentName, @@ -1048,6 +1095,10 @@ public class UpgradeResourceProvider extends AbstractControllerResourceProvider // Apply additional parameters to the command that come from the stage. applyAdditionalParameters(wrapper, commandParams); + // add things like hooks and service folders based on effective repo + applyRepositoryAssociatedParameters(wrapper, effectiveRepositoryVersion.getStackId(), + commandParams); + ActionExecutionContext actionContext = new ActionExecutionContext(cluster.getClusterName(), "SERVICE_CHECK", filters, commandParams); http://git-wip-us.apache.org/repos/asf/ambari/blob/e87a3e31/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/historyserver.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/historyserver.py b/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/historyserver.py index d886244..0b03af4 100644 --- a/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/historyserver.py +++ b/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/historyserver.py @@ -90,7 +90,7 @@ class HistoryServerDefault(HistoryServer): env.set_params(params) self.configure(env) # FOR SECURITY - if params.stack_version_formatted_major and check_stack_feature(StackFeature.COPY_TARBALL_TO_HDFS, params.stack_version_formatted_major): + if check_stack_feature(StackFeature.COPY_TARBALL_TO_HDFS, params.version_for_stack_feature_checks): # MC Hammer said, "Can't touch this" resource_created = copy_to_hdfs( "mapreduce", http://git-wip-us.apache.org/repos/asf/ambari/blob/e87a3e31/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/params_linux.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/params_linux.py b/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/params_linux.py index 67931c6..6f75852 100644 --- a/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/params_linux.py +++ b/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/params_linux.py @@ -66,21 +66,20 @@ tarball_map = default("/configurations/cluster-env/tarball_map", None) config_path = os.path.join(stack_root, "current/hadoop-client/conf") config_dir = os.path.realpath(config_path) +# get the correct version to use for checking stack features +version_for_stack_feature_checks = get_stack_feature_version(config) + # This is expected to be of the form #.#.#.# stack_version_unformatted = config['hostLevelParams']['stack_version'] -stack_version_formatted_major = format_stack_version(stack_version_unformatted) stack_version_formatted = functions.get_stack_version('hadoop-yarn-resourcemanager') -stack_supports_ru = stack_version_formatted_major and check_stack_feature(StackFeature.ROLLING_UPGRADE, stack_version_formatted_major) -stack_supports_timeline_state_store = stack_version_formatted_major and check_stack_feature(StackFeature.TIMELINE_STATE_STORE, stack_version_formatted_major) +stack_supports_ru = check_stack_feature(StackFeature.ROLLING_UPGRADE, version_for_stack_feature_checks) +stack_supports_timeline_state_store = check_stack_feature(StackFeature.TIMELINE_STATE_STORE, version_for_stack_feature_checks) # New Cluster Stack Version that is defined during the RESTART of a Stack Upgrade. # It cannot be used during the initial Cluser Install because the version is not yet known. version = default("/commandParams/version", None) -# get the correct version to use for checking stack features -version_for_stack_feature_checks = get_stack_feature_version(config) - stack_supports_ranger_kerberos = check_stack_feature(StackFeature.RANGER_KERBEROS_SUPPORT, version_for_stack_feature_checks) stack_supports_ranger_audit_db = check_stack_feature(StackFeature.RANGER_AUDIT_DB_SUPPORT, version_for_stack_feature_checks) http://git-wip-us.apache.org/repos/asf/ambari/blob/e87a3e31/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/service_check.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/service_check.py b/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/service_check.py index b934767..bf52ee6 100644 --- a/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/service_check.py +++ b/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/package/scripts/service_check.py @@ -99,11 +99,7 @@ class ServiceCheckDefault(ServiceCheck): mode=params.smoke_hdfs_user_mode, ) - if params.stack_version_formatted_major and check_stack_feature(StackFeature.ROLLING_UPGRADE, params.stack_version_formatted_major): - path_to_distributed_shell_jar = format("{stack_root}/current/hadoop-yarn-client/hadoop-yarn-applications-distributedshell.jar") - else: - path_to_distributed_shell_jar = "/usr/lib/hadoop-yarn/hadoop-yarn-applications-distributedshell*.jar" - + path_to_distributed_shell_jar = format("{stack_root}/current/hadoop-yarn-client/hadoop-yarn-applications-distributedshell.jar") yarn_distrubuted_shell_check_params = ["yarn org.apache.hadoop.yarn.applications.distributedshell.Client", "-shell_command", "ls", "-num_containers", "{number_of_nm}", "-jar", "{path_to_distributed_shell_jar}", "-timeout", "300000", http://git-wip-us.apache.org/repos/asf/ambari/blob/e87a3e31/ambari-server/src/test/python/TestStackFeature.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/python/TestStackFeature.py b/ambari-server/src/test/python/TestStackFeature.py index 230734c..6e8bcec 100644 --- a/ambari-server/src/test/python/TestStackFeature.py +++ b/ambari-server/src/test/python/TestStackFeature.py @@ -21,10 +21,13 @@ limitations under the License. from resource_management.core.logger import Logger from resource_management.libraries.functions.stack_features import get_stack_feature_version +from resource_management.libraries.functions.stack_features import check_stack_feature from resource_management.libraries.script import Script from resource_management.core.exceptions import Fail from unittest import TestCase +import json + Logger.initialize_logger() class TestStackFeature(TestCase): @@ -115,6 +118,34 @@ class TestStackFeature(TestCase): stack_feature_version = get_stack_feature_version(command_json) self.assertEqual("2.5.9.9-9999", stack_feature_version) + + def test_get_stack_feature(self): + """ + Tests the stack feature version calculated during a STOP command in a downgrade. + :return: + """ + command_json = TestStackFeature._get_cluster_upgrade_restart_json() + Script.config = command_json + + Script.config["configurations"] = {} + Script.config["configurations"]["cluster-env"] = {} + Script.config["configurations"]["cluster-env"]["stack_features"] = {} + Script.config["configurations"]["cluster-env"]["stack_features"] = json.dumps(TestStackFeature._get_stack_feature_json()) + + stack_feature_version = get_stack_feature_version(command_json) + self.assertTrue(check_stack_feature("stack-feature-1", stack_feature_version)) + self.assertTrue(check_stack_feature("stack-feature-2", stack_feature_version)) + self.assertFalse(check_stack_feature("stack-feature-3", stack_feature_version)) + + command_json = TestStackFeature._get_cluster_install_command_json() + Script.config.update(command_json) + + stack_feature_version = get_stack_feature_version(command_json) + self.assertTrue(check_stack_feature("stack-feature-1", stack_feature_version)) + self.assertTrue(check_stack_feature("stack-feature-2", stack_feature_version)) + self.assertFalse(check_stack_feature("stack-feature-3", stack_feature_version)) + + @staticmethod def _get_cluster_install_command_json(): """ @@ -221,4 +252,34 @@ class TestStackFeature(TestCase): "version":"2.5.9.9-9999", "downgrade_from_version":"2.5.9.9-9999" } + } + + @staticmethod + def _get_stack_feature_json(): + """ + A STOP command during a downgrade. + :return: + """ + return { + "HDP": { + "stack_features":[ + { + "name":"stack-feature-1", + "description":"Stack Feature 1", + "min_version":"2.2.0.0" + }, + { + "name":"stack-feature-2", + "description":"Stack Feature 2", + "min_version":"2.2.0.0", + "max_version":"2.6.0.0" + }, + { + "name":"stack-feature-3", + "description":"Stack Feature 3", + "min_version":"2.2.0.0", + "max_version":"2.3.0.0" + } + ] + } } \ No newline at end of file