Repository: ambari Updated Branches: refs/heads/trunk cc82fec86 -> 8eead1491
AMBARI-18637: Management pack purge option should warn user and ask for confirmation before purging (jluniya) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/8eead149 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/8eead149 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/8eead149 Branch: refs/heads/trunk Commit: 8eead14916ddd86658c488dd07f9432dadcc2331 Parents: cc82fec Author: Jayush Luniya <[email protected]> Authored: Tue Oct 25 22:20:45 2016 +0900 Committer: Jayush Luniya <[email protected]> Committed: Tue Oct 25 22:20:45 2016 +0900 ---------------------------------------------------------------------- .../server/checks/MpackInstallChecker.java | 240 +++++++++++++++++++ .../main/python/ambari_server/setupMpacks.py | 106 +++++++- .../server/checks/MpackInstallCheckerTest.java | 124 ++++++++++ ambari-server/src/test/python/TestMpacks.py | 61 ++++- 4 files changed, 522 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/8eead149/ambari-server/src/main/java/org/apache/ambari/server/checks/MpackInstallChecker.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/checks/MpackInstallChecker.java b/ambari-server/src/main/java/org/apache/ambari/server/checks/MpackInstallChecker.java new file mode 100644 index 0000000..d80f123 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/checks/MpackInstallChecker.java @@ -0,0 +1,240 @@ +/* + * 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. + */ +package org.apache.ambari.server.checks; + +import com.google.inject.Guice; +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.persist.PersistService; + +import org.apache.ambari.server.audit.AuditLoggerModule; +import org.apache.ambari.server.controller.ControllerModule; +import org.apache.ambari.server.orm.DBAccessor; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + + +/** + * Mpack Install Checker + */ +public class MpackInstallChecker { + + private static final String MPACK_STACKS_ARG = "mpack-stacks"; + + private static final Logger LOG = LoggerFactory.getLogger + (MpackInstallChecker.class); + + private PersistService persistService; + private DBAccessor dbAccessor; + private Injector injector; + private Connection connection; + + private boolean errorsFound = false; + + private static Options getOptions() { + Options options = new Options(); + options.addOption(Option.builder().longOpt(MPACK_STACKS_ARG).desc( + "List of stacks defined in the management pack").required().type(String.class).hasArg().valueSeparator(' ').build()); + return options; + } + + private static MpackContext processArguments(String... args) { + CommandLineParser cmdLineParser = new DefaultParser(); + HelpFormatter formatter = new HelpFormatter(); + MpackContext ctx = null; + + try { + CommandLine line = cmdLineParser.parse(getOptions(), args); + String mpackStacksStr = (String) line.getParsedOptionValue(MPACK_STACKS_ARG); + HashSet<String> stacksInMpack = new HashSet<>(Arrays.asList(mpackStacksStr.split(","))); + ctx = new MpackContext(stacksInMpack); + } catch (Exception exp) { + System.err.println("Parsing failed. Reason: " + exp.getMessage()); + LOG.error("Parsing failed. Reason: ", exp); + System.exit(1); + } + return ctx; + } + + public boolean isErrorsFound() { + return errorsFound; + } + + @Inject + public MpackInstallChecker(DBAccessor dbAccessor, + Injector injector, + PersistService persistService) { + this.dbAccessor = dbAccessor; + this.injector = injector; + this.persistService = persistService; + } + + /** + * Extension of audit logger module + */ + public static class MpackCheckerAuditModule extends AuditLoggerModule { + + public MpackCheckerAuditModule() throws Exception { + } + + @Override + protected void configure() { + super.configure(); + } + } + + public void startPersistenceService() { + persistService.start(); + } + + public void stopPersistenceService() { + persistService.stop(); + } + + public Connection getConnection() { + if (connection == null) { + if (dbAccessor == null) { + dbAccessor = injector.getInstance(DBAccessor.class); + } + connection = dbAccessor.getConnection(); + } + return connection; + } + + /** + * Check if any clusters are deployed with a stack that is not included in the management pack + * @param stacksInMpack List of stacks included in the management pack + */ + public void checkClusters(HashSet<String> stacksInMpack) { + + ResultSet rs = null; + Statement statement = null; + Map<String, Map<String, String>> clusterStackInfo = new HashMap<>(); + String GET_STACK_NAME_VERSION_QUERY = "select c.cluster_name, s.stack_name, s.stack_version from clusters c " + + "join stack s on c.desired_stack_id = s.stack_id"; + + Connection conn = getConnection(); + try { + statement = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); + rs = statement.executeQuery(GET_STACK_NAME_VERSION_QUERY); + if (rs != null) { + while (rs.next()) { + Map<String, String> stackInfoMap = new HashMap<>(); + stackInfoMap.put(rs.getString("stack_name"), rs.getString("stack_version")); + clusterStackInfo.put(rs.getString("cluster_name"), stackInfoMap); + } + } + + for (Map.Entry<String, Map<String, String>> clusterStackInfoEntry : clusterStackInfo.entrySet()) { + String clusterName = clusterStackInfoEntry.getKey(); + Map<String, String> stackInfo = clusterStackInfoEntry.getValue(); + String stackName = stackInfo.keySet().iterator().next(); + String stackVersion = stackInfo.get(stackName); + if(!stacksInMpack.contains(stackName)) { + String errorMsg = String.format("This Ambari instance is already managing the cluster %s that has the " + + "%s-%s stack installed on it. The management pack you are attempting to install only contains stack " + + "definitions for %s. Since this management pack does not contain a stack that has already being " + + "deployed by Ambari, the --purge option would cause your existing Ambari installation to be unusable. " + + "Due to that we cannot install this management pack.", + clusterName, stackName, stackVersion, stacksInMpack.toString()); + LOG.error(errorMsg); + System.err.println(errorMsg); + errorsFound = true; + } + } + } catch (SQLException e) { + System.err.println("SQL Exception occured during check for validating installed clusters. Reason: " + e.getMessage()); + LOG.error("SQL Exception occured during check for validating installed clusters. Reason: ", e); + errorsFound = true; + } finally { + if (rs != null) { + try { + rs.close(); + } catch (SQLException e) { + System.err.println("SQL Exception occurred during result set closing procedure. Reason: " + e.getMessage()); + LOG.error("SQL Exception occurred during result set closing procedure. Reason: " , e); + errorsFound = true; + } + } + if (statement != null) { + try { + statement.close(); + } catch (SQLException e) { + System.err.println("SQL Exception occurred during statement closing procedure. Reason: " + e.getMessage()); + LOG.error("SQL Exception occurred during statement closing procedure. Reason: ", e); + errorsFound = true; + } + } + } + } + + /** + * Main method for management pack installation checker + */ + public static void main(String[] args) throws Exception { + + Injector injector = Guice.createInjector(new ControllerModule(), new MpackCheckerAuditModule()); + MpackInstallChecker mpackInstallChecker = injector.getInstance(MpackInstallChecker.class); + MpackContext mpackContext = processArguments(args); + + mpackInstallChecker.startPersistenceService(); + + mpackInstallChecker.checkClusters(mpackContext.getStacksInMpack()); + + mpackInstallChecker.stopPersistenceService(); + + if(mpackInstallChecker.isErrorsFound()) { + LOG.error("Mpack installation checker failed!"); + System.err.println("Mpack installation checker failed!"); + System.exit(1); + } else { + LOG.info("No errors found"); + System.out.println("No errors found"); + } + } + + /** + * Context object that encapsulates values passed in as arguments to the {@link MpackInstallChecker} class. + */ + private static class MpackContext { + private HashSet<String> stacksInMpack; + + public MpackContext(HashSet<String> stacksInMpack) { + this.stacksInMpack = stacksInMpack; + } + + public HashSet<String> getStacksInMpack() { + return stacksInMpack; + } + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/8eead149/ambari-server/src/main/python/ambari_server/setupMpacks.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/python/ambari_server/setupMpacks.py b/ambari-server/src/main/python/ambari_server/setupMpacks.py index 4ffeb42..f0c4f86 100644 --- a/ambari-server/src/main/python/ambari_server/setupMpacks.py +++ b/ambari-server/src/main/python/ambari_server/setupMpacks.py @@ -24,17 +24,27 @@ import json import ast import logging +from ambari_server.serverClassPath import ServerClassPath + from ambari_commons.exceptions import FatalException from ambari_commons.inet_utils import download_file -from ambari_commons.logging_utils import print_info_msg, print_error_msg +from ambari_commons.logging_utils import print_info_msg, print_error_msg, print_warning_msg from ambari_commons.os_utils import copy_file, run_os_command from ambari_server.serverConfiguration import get_ambari_properties, get_ambari_version, get_stack_location, \ - get_common_services_location, get_mpacks_staging_location, get_server_temp_location, get_extension_location + get_common_services_location, get_mpacks_staging_location, get_server_temp_location, get_extension_location, \ + get_java_exe_path, read_ambari_user, parse_properties_file, JDBC_DATABASE_PROPERTY +from ambari_server.setupSecurity import ensure_can_start_under_current_user, generate_env +from ambari_server.setupActions import INSTALL_MPACK_ACTION, UPGRADE_MPACK_ACTION +from ambari_server.userInput import get_YN_input +from ambari_server.dbConfiguration import ensure_jdbc_driver_is_installed, LINUX_DBMS_KEYS_LIST from resource_management.core import sudo from resource_management.libraries.functions.tar_archive import extract_archive, get_archive_root_dir from resource_management.libraries.functions.version import compare_versions -from ambari_server.setupActions import INSTALL_MPACK_ACTION, UPGRADE_MPACK_ACTION + + +MPACK_INSTALL_CHECKER_CMD = "{0} -cp {1} " + \ + "org.apache.ambari.server.checks.MpackInstallChecker --mpack-stacks {2}" logger = logging.getLogger(__name__) @@ -57,6 +67,11 @@ SERVICE_DEFINITIONS_ARTIFACT_NAME = "service-definitions" EXTENSION_DEFINITIONS_ARTIFACT_NAME = "extension-definitions" STACK_ADDON_SERVICE_DEFINITIONS_ARTIFACT_NAME = "stack-addon-service-definitions" +RESOURCE_FRIENDLY_NAMES = { + STACK_DEFINITIONS_RESOURCE_NAME : "stack definitions", + SERVICE_DEFINITIONS_RESOURCE_NAME: "service definitions", + MPACKS_RESOURCE_NAME: "management packs" +} class _named_dict(dict): """ @@ -236,6 +251,85 @@ def remove_symlinks(stack_location, service_definitions_location, staged_mpack_d print_info_msg("Removing symlink {0}".format(dir)) sudo.unlink(dir) +def run_mpack_install_checker(options, mpack_stacks): + """ + Run MpackInstallChecker to validate that there is no cluster deployed with a stack that is not included in the management pack + :param options: Options passed + :param mpack_stacks: List of stacks included in the management pack + :return: Output of MpackInstallChecker + """ + properties = get_ambari_properties() + database_type = properties[JDBC_DATABASE_PROPERTY] + jdk_path = get_java_exe_path() + + if not jdk_path or not database_type: + # Ambari Server has not been setup, so no cluster would be present + return (0, "", "") + + parse_properties_file(options) + options.database_index = LINUX_DBMS_KEYS_LIST.index(properties[JDBC_DATABASE_PROPERTY]) + ensure_jdbc_driver_is_installed(options, properties) + + serverClassPath = ServerClassPath(properties, options) + class_path = serverClassPath.get_full_ambari_classpath_escaped_for_shell() + + command = MPACK_INSTALL_CHECKER_CMD.format(jdk_path, class_path, ",".join(mpack_stacks)) + + ambari_user = read_ambari_user() + current_user = ensure_can_start_under_current_user(ambari_user) + environ = generate_env(options, ambari_user, current_user) + + return run_os_command(command, env=environ) + + +def validate_purge(options, purge_list, mpack_dir, mpack_metadata, replay_mode=False): + """ + Validate purge options + :param purge_list: List of resources to purge + :param mpack_metadata: Management pack metadata + :param replay_mode: Flag to indicate if purging in replay mode + """ + # Get ambari mpacks config properties + stack_location, extension_location, service_definitions_location, mpacks_staging_location = get_mpack_properties() + + if not purge_list: + return + + if STACK_DEFINITIONS_RESOURCE_NAME in purge_list: + mpack_stacks = [] + for artifact in mpack_metadata.artifacts: + if artifact.type == STACK_DEFINITIONS_ARTIFACT_NAME: + artifact_source_dir = os.path.join(mpack_dir, artifact.source_dir) + for file in sorted(os.listdir(artifact_source_dir)): + if os.path.isdir(os.path.join(artifact_source_dir, file)): + stack_name = file + mpack_stacks.append(stack_name) + if not mpack_stacks: + # Don't purge stacks accidentally when installing add-on mpacks + err = "The management pack you are attempting to install does not contain {0}. Since this management pack " \ + "does not contain a stack, the --purge option with --purge-list={1} would cause your existing Ambari " \ + "installation to be unusable. Due to that we cannot install this management pack.".format( + RESOURCE_FRIENDLY_NAMES[STACK_DEFINITIONS_ARTIFACT_NAME], purge_list) + print_error_msg(err) + raise FatalException(1, err) + else: + # Valid that there are no clusters deployed with a stack that is not included in the management pack + (retcode, stdout, stderr) = run_mpack_install_checker(options, mpack_stacks) + if retcode > 0: + print_error_msg(stderr) + raise FatalException(1, stderr) + + if not replay_mode: + purge_resources = set((v) for k, v in RESOURCE_FRIENDLY_NAMES.iteritems() if k in purge_list) + warn_msg = "CAUTION: You have specified the --purge option with --purge-list={0}. " \ + "This will replace all existing {1} currently installed.\n" \ + "Are you absolutely sure you want to perform the purge [yes/no]? (no)".format( + purge_list, ", ".join(purge_resources)) + okToPurge = get_YN_input(warn_msg, False) + if not okToPurge: + err = "Management pack installation cancelled by user" + raise FatalException(1, err) + def purge_stacks_and_mpacks(purge_list, replay_mode=False): """ Purge all stacks and management packs @@ -464,7 +558,7 @@ def uninstall_mpack(mpack_name, mpack_version): def validate_mpack_prerequisites(mpack_metadata): """ Validate management pack prerequisites - :param mpack_name: Management pack metadata + :param mpack_metadata: Management pack metadata """ # Get ambari config properties properties = get_ambari_properties() @@ -547,7 +641,9 @@ def _install_mpack(options, replay_mode=False, is_upgrade=False): # Purge previously installed stacks and management packs if options.purge and options.purge_list: - purge_stacks_and_mpacks(options.purge_list.split(","), replay_mode) + purge_resources = options.purge_list.split(",") + validate_purge(options, purge_resources, tmp_root_dir, mpack_metadata, replay_mode) + purge_stacks_and_mpacks(purge_resources, replay_mode) # Get ambari mpack properties stack_location, extension_location, service_definitions_location, mpacks_staging_location = get_mpack_properties() http://git-wip-us.apache.org/repos/asf/ambari/blob/8eead149/ambari-server/src/test/java/org/apache/ambari/server/checks/MpackInstallCheckerTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/checks/MpackInstallCheckerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/checks/MpackInstallCheckerTest.java new file mode 100644 index 0000000..634fe70 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/checks/MpackInstallCheckerTest.java @@ -0,0 +1,124 @@ +/* + * 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. + */ +package org.apache.ambari.server.checks; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import junit.framework.Assert; +import org.apache.ambari.server.orm.DBAccessor; +import org.apache.ambari.server.stack.StackManagerFactory; +import org.apache.ambari.server.state.Clusters; +import org.apache.ambari.server.state.stack.OsFamily; +import org.easymock.EasyMockSupport; +import org.junit.Test; +import com.google.inject.persist.PersistService; +import javax.persistence.EntityManager; +import static org.easymock.EasyMock.expect; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.HashSet; + +/** + * Unit tests for {@link MpackInstallChecker} + */ +public class MpackInstallCheckerTest { + + @Test + public void testCheckValidClusters() throws Exception { + + EasyMockSupport easyMockSupport = new EasyMockSupport(); + final Connection mockConnection = easyMockSupport.createNiceMock(Connection.class); + final Statement mockStatement = easyMockSupport.createNiceMock(Statement.class); + final ResultSet stackResultSet = easyMockSupport.createNiceMock(ResultSet.class); + + final DBAccessor mockDBDbAccessor = easyMockSupport.createNiceMock(DBAccessor.class); + final PersistService mockPersistService = easyMockSupport.createNiceMock(PersistService.class); + final Injector mockInjector = Guice.createInjector(new AbstractModule() { + @Override + protected void configure() { + bind(DBAccessor.class).toInstance(mockDBDbAccessor); + bind(PersistService.class).toInstance(mockPersistService); + } + }); + + MpackInstallChecker mpackInstallChecker = mockInjector.getInstance(MpackInstallChecker.class); + + HashSet<String> stacksInMpack = new HashSet<>(); + stacksInMpack.add("HDF"); + + expect(mpackInstallChecker.getConnection()).andReturn(mockConnection); + expect(mockConnection.createStatement( + ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)).andReturn(mockStatement); + expect(mockStatement.executeQuery("select c.cluster_name, s.stack_name, s.stack_version from clusters c " + + "join stack s on c.desired_stack_id = s.stack_id")).andReturn(stackResultSet); + expect(stackResultSet.next()).andReturn(true); + expect(stackResultSet.getString("stack_name")).andReturn("HDF"); + expect(stackResultSet.getString("stack_version")).andReturn("2.0"); + expect(stackResultSet.getString("cluster_name")).andReturn("cl1"); + + easyMockSupport.replayAll(); + mpackInstallChecker.checkClusters(stacksInMpack); + easyMockSupport.verifyAll(); + + Assert.assertFalse("No errors should have been triggered.", mpackInstallChecker.isErrorsFound()); + } + + @Test + public void testCheckInvalidClusters() throws Exception { + + EasyMockSupport easyMockSupport = new EasyMockSupport(); + final Connection mockConnection = easyMockSupport.createNiceMock(Connection.class); + final Statement mockStatement = easyMockSupport.createNiceMock(Statement.class); + final ResultSet stackResultSet = easyMockSupport.createNiceMock(ResultSet.class); + + final DBAccessor mockDBDbAccessor = easyMockSupport.createNiceMock(DBAccessor.class); + final PersistService mockPersistService = easyMockSupport.createNiceMock(PersistService.class); + final Injector mockInjector = Guice.createInjector(new AbstractModule() { + @Override + protected void configure() { + bind(DBAccessor.class).toInstance(mockDBDbAccessor); + bind(PersistService.class).toInstance(mockPersistService); + } + }); + MpackInstallChecker mpackInstallChecker = mockInjector.getInstance(MpackInstallChecker.class); + + HashSet<String> stacksInMpack = new HashSet<>(); + stacksInMpack.add("HDF"); + + expect(mpackInstallChecker.getConnection()).andReturn(mockConnection); + expect(mockConnection.createStatement( + ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)).andReturn(mockStatement); + expect(mockStatement.executeQuery("select c.cluster_name, s.stack_name, s.stack_version from clusters c " + + "join stack s on c.desired_stack_id = s.stack_id")).andReturn(stackResultSet); + expect(stackResultSet.next()).andReturn(true); + expect(stackResultSet.getString("stack_name")).andReturn("HDP"); + expect(stackResultSet.getString("stack_version")).andReturn("2.5"); + expect(stackResultSet.getString("cluster_name")).andReturn("cl1"); + + easyMockSupport.replayAll(); + mpackInstallChecker.checkClusters(stacksInMpack); + easyMockSupport.verifyAll(); + + Assert.assertTrue("Installing HDF mpack on HDP cluster with purge option should have triggered an error.", + mpackInstallChecker.isErrorsFound()); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/8eead149/ambari-server/src/test/python/TestMpacks.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/python/TestMpacks.py b/ambari-server/src/test/python/TestMpacks.py index d0ef461..d935b5a 100644 --- a/ambari-server/src/test/python/TestMpacks.py +++ b/ambari-server/src/test/python/TestMpacks.py @@ -48,8 +48,8 @@ with patch.object(platform, "linux_distribution", return_value = MagicMock(retur serverConfiguration.search_file = _search_file from ambari_server.setupMpacks import install_mpack, upgrade_mpack, replay_mpack_logs, \ - purge_stacks_and_mpacks, STACK_DEFINITIONS_RESOURCE_NAME, SERVICE_DEFINITIONS_RESOURCE_NAME, \ - MPACKS_RESOURCE_NAME + purge_stacks_and_mpacks, validate_purge, read_mpack_metadata, \ + STACK_DEFINITIONS_RESOURCE_NAME, SERVICE_DEFINITIONS_RESOURCE_NAME, MPACKS_RESOURCE_NAME with patch.object(os, "geteuid", new=MagicMock(return_value=0)): from resource_management.core import sudo @@ -63,7 +63,8 @@ def get_configs(): serverConfiguration.COMMON_SERVICES_PATH_PROPERTY : "/var/lib/ambari-server/resources/common-services", serverConfiguration.EXTENSION_PATH_PROPERTY : "/var/lib/ambari-server/resources/extensions", serverConfiguration.MPACKS_STAGING_PATH_PROPERTY : mpacks_directory, - serverConfiguration.SERVER_TMP_DIR_PROPERTY : "/tmp" + serverConfiguration.SERVER_TMP_DIR_PROPERTY : "/tmp", + serverConfiguration.JDBC_DATABASE_PROPERTY: "postgres" } return configs @@ -95,6 +96,57 @@ class TestMpacks(TestCase): fail = True self.assertTrue(fail) + @patch("ambari_server.setupMpacks.get_YN_input") + @patch("ambari_server.setupMpacks.run_mpack_install_checker") + def test_validate_purge(self, run_mpack_install_checker_mock, get_YN_input_mock): + options = self._create_empty_options_mock() + options.purge = True + purge_list = options.purge_list.split(',') + mpack_staging_dir = configs[serverConfiguration.MPACKS_STAGING_PATH_PROPERTY] + mpack_dir = os.path.join(mpack_staging_dir, "mystack-ambari-mpack-1.0.0.0") + mpack_metadata = read_mpack_metadata(mpack_dir) + replay_mode = False + run_mpack_install_checker_mock.return_value = (0, "No errors found", "") + get_YN_input_mock.return_value = True + + fail = False + try: + validate_purge(options, purge_list, mpack_dir, mpack_metadata, replay_mode) + except FatalException as e: + # Unexpected failure + fail = True + self.assertFalse(fail) + + get_YN_input_mock.return_value = False + fail = False + try: + validate_purge(options, purge_list, mpack_dir, mpack_metadata, replay_mode) + except FatalException as e: + # Expected failure + fail = True + self.assertTrue(fail) + + get_YN_input_mock.return_value = True + fail = False + run_mpack_install_checker_mock.return_value = (1, "", "Mpack installation checker failed!") + try: + validate_purge(options, purge_list, mpack_dir, mpack_metadata, replay_mode) + except FatalException as e: + # Expected failure + fail = True + self.assertTrue(fail) + + fail = False + mpack_dir = os.path.join(mpack_staging_dir, "myservice-ambari-mpack-1.0.0.0") + mpack_metadata = read_mpack_metadata(mpack_dir) + run_mpack_install_checker_mock.return_value = (0, "No errors found", "") + try: + validate_purge(options, purge_list, mpack_dir, mpack_metadata, replay_mode) + except FatalException as e: + # Expected failure + fail = True + self.assertTrue(fail) + @patch("os.path.exists") @patch("ambari_server.setupMpacks.get_ambari_properties") def test_purge_stacks_and_mpacks(self, get_ambari_version_mock, os_path_exists_mock): @@ -188,7 +240,8 @@ class TestMpacks(TestCase): @patch("ambari_server.setupMpacks.expand_mpack") @patch("ambari_server.setupMpacks.download_mpack") @patch("ambari_server.setupMpacks.run_os_command") - def test_install_stack_mpack(self, run_os_command_mock, download_mpack_mock, expand_mpack_mock, purge_stacks_and_mpacks_mock, + @patch("ambari_server.setupMpacks.validate_purge") + def test_install_stack_mpack(self, validate_purge_mock, run_os_command_mock, download_mpack_mock, expand_mpack_mock, purge_stacks_and_mpacks_mock, add_replay_log_mock, get_ambari_properties_mock, get_ambari_version_mock, create_symlink_mock, os_mkdir_mock, shutil_move_mock, os_path_exists_mock): options = self._create_empty_options_mock()
