Repository: ambari Updated Branches: refs/heads/branch-2.4 8de7bbd90 -> 05cff453b refs/heads/trunk 4edadd787 -> 2de48e49f
AMBARI-17198. Failure in mahout package installation upon retry is not correctly reported causing EU to fail (dgrinenko via dlysnichenko) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/2de48e49 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/2de48e49 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/2de48e49 Branch: refs/heads/trunk Commit: 2de48e49ff4c4e33150b98cfb103828c8ae913f1 Parents: 4edadd7 Author: Lisnichenko Dmitro <[email protected]> Authored: Wed Jun 15 12:44:33 2016 +0300 Committer: Lisnichenko Dmitro <[email protected]> Committed: Wed Jun 15 12:44:33 2016 +0300 ---------------------------------------------------------------------- .../resource_management/TestPackagesAnalyzer.py | 58 +++++++++++++++++++- .../libraries/functions/packages_analyzer.py | 37 +++++++++++++ .../custom_actions/scripts/install_packages.py | 15 ++++- 3 files changed, 106 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/2de48e49/ambari-agent/src/test/python/resource_management/TestPackagesAnalyzer.py ---------------------------------------------------------------------- diff --git a/ambari-agent/src/test/python/resource_management/TestPackagesAnalyzer.py b/ambari-agent/src/test/python/resource_management/TestPackagesAnalyzer.py index 73484f3..36dfdd0 100644 --- a/ambari-agent/src/test/python/resource_management/TestPackagesAnalyzer.py +++ b/ambari-agent/src/test/python/resource_management/TestPackagesAnalyzer.py @@ -17,7 +17,8 @@ limitations under the License. ''' from unittest import TestCase from mock.mock import patch, MagicMock, call -from ambari_commons.os_check import OSCheck +from ambari_commons.os_check import OSCheck, OSConst +from resource_management.core.exceptions import Fail from resource_management.libraries.functions import packages_analyzer class TestPackagesAnalyzer(TestCase): @@ -39,6 +40,61 @@ class TestPackagesAnalyzer(TestCase): self.assertEqual(result, '0.0.1-SNAPSHOT') self.assertEqual(checked_call_mock.call_args_list, [call("rpm -q --queryformat '%{version}-%{release}' package1 | sed -e 's/\\.el[0-9]//g'", stderr=-1)]) + @patch("resource_management.libraries.functions.packages_analyzer.rmf_shell.checked_call") + @patch.object(OSCheck, "is_in_family") + @patch.object(packages_analyzer, "Logger") + def test_vefify_dependency_suse(self, logger_mock, in_family_patch_mock, checked_call_mock): + test_cases = [ + { + "name": "SUSE Case", + "os": OSConst.SUSE_FAMILY, + "cheked_call_result": "5 new packages to install" + }, + { + "name": "REDHAT Case", + "os": OSConst.REDHAT_FAMILY, + "cheked_call_result": "Error:" + }, + { + "name": "UBUNTU Case", + "os": OSConst.UBUNTU_FAMILY, + "cheked_call_result": "E:" + } + ] + + for test_case in test_cases: + in_family_patch_mock.side_effect = lambda current_family, family: family == test_case["os"] + checked_call_mock.return_value = (0, "OK.") + + # happy scenario + self.assertTrue(packages_analyzer.verifyDependencies(), "test_verify_dependency failed on '%s'" % test_case["name"]) + + # unhappy scenario + checked_call_mock.return_value = (0, test_case["cheked_call_result"]) + self.assertFalse(packages_analyzer.verifyDependencies(), "test_verify_dependency failed on '%s'" % test_case["name"]) + + # + try: + in_family_patch_mock.side_effect = lambda current_family, family: False + packages_analyzer.verifyDependencies() + self.assertTrue(False, "Wrong handling of unknown operation system") + except Fail: + pass + + @patch("resource_management.libraries.functions.packages_analyzer.rmf_shell.checked_call") + @patch.object(OSCheck, "is_in_family") + def test_vefify_dependency_redhat(self, in_family_patch_mock, checked_call_mock): + in_family_patch_mock.side_effect = lambda current_family, family: family == OSConst.REDHAT_FAMILY + checked_call_mock.return_value = (0, "OK.") + pass + + @patch("resource_management.libraries.functions.packages_analyzer.rmf_shell.checked_call") + @patch.object(OSCheck, "is_in_family") + def test_vefify_dependency_ubuntu(self, in_family_patch_mock, checked_call_mock): + in_family_patch_mock.side_effect = lambda current_family, family: family == OSConst.UBUNTU_FAMILY + checked_call_mock.return_value = (0, "OK.") + pass + def test_perform_package_analysis(self): installedPackages = [ ["hadoop-a", "2.3", "HDP"], ["zk", "3.1", "HDP"], ["webhcat", "3.1", "HDP"], http://git-wip-us.apache.org/repos/asf/ambari/blob/2de48e49/ambari-common/src/main/python/resource_management/libraries/functions/packages_analyzer.py ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/resource_management/libraries/functions/packages_analyzer.py b/ambari-common/src/main/python/resource_management/libraries/functions/packages_analyzer.py index 7a21958..860c1af 100644 --- a/ambari-common/src/main/python/resource_management/libraries/functions/packages_analyzer.py +++ b/ambari-common/src/main/python/resource_management/libraries/functions/packages_analyzer.py @@ -26,7 +26,9 @@ from threading import Thread import threading from ambari_commons import OSCheck, OSConst from ambari_commons import shell +from resource_management.core.logger import Logger from resource_management.core import shell as rmf_shell +from resource_management.core.exceptions import Fail __all__ = ["installedPkgsByName", "allInstalledPackages", "allAvailablePackages", "nameMatch", "getInstalledRepos", "getInstalledPkgsByRepo", "getInstalledPkgsByNames", "getPackageDetails"] @@ -279,3 +281,38 @@ def getInstalledPackageVersion(package_name): code, out, err = rmf_shell.checked_call("rpm -q --queryformat '%{{version}}-%{{release}}' {0} | sed -e 's/\.el[0-9]//g'".format(package_name), stderr=subprocess.PIPE) return out + + +def verifyDependencies(): + """ + Verify that we have no dependency issues in package manager. Dependency issues could appear because of aborted or terminated + package installation process or invalid packages state after manual modification of packages list on the host + :return True if no dependency issues found, False if dependency issue present + :rtype bool + """ + check_str = None + cmd = None + + if OSCheck.is_redhat_family(): + cmd = ['/usr/bin/yum', '-d', '0', '-e', '0', 'check', 'dependencies'] + check_str = "has missing requires|Error:" + elif OSCheck.is_suse_family(): + cmd = ['/usr/bin/zypper', '--quiet', '--non-interactive' 'verify', '--dry-run'] + check_str = "\d+ new package(s)? to install" + elif OSCheck.is_ubuntu_family(): + cmd = ['/usr/bin/apt-get', '-qq', 'check'] + check_str = "has missing dependency|E:" + + if check_str is None or cmd is None: + raise Fail("Unsupported OSFamily on the Agent Host") + + code, out = rmf_shell.checked_call(cmd) + + output_regex = re.compile(check_str) + + if code or (out and output_regex.search(out)): + err_msg = Logger.filter_text("Failed to verify package dependencies. Execution of '%s' returned %s. %s" % (cmd, code, out)) + Logger.error(err_msg) + return False + + return True http://git-wip-us.apache.org/repos/asf/ambari/blob/2de48e49/ambari-server/src/main/resources/custom_actions/scripts/install_packages.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/custom_actions/scripts/install_packages.py b/ambari-server/src/main/resources/custom_actions/scripts/install_packages.py index 3133984..0e31310 100644 --- a/ambari-server/src/main/resources/custom_actions/scripts/install_packages.py +++ b/ambari-server/src/main/resources/custom_actions/scripts/install_packages.py @@ -32,7 +32,7 @@ import resource_management from resource_management.libraries.functions.list_ambari_managed_repos import list_ambari_managed_repos from ambari_commons.os_check import OSCheck, OSConst from ambari_commons.str_utils import cbool, cint -from resource_management.libraries.functions.packages_analyzer import allInstalledPackages +from resource_management.libraries.functions.packages_analyzer import allInstalledPackages, verifyDependencies from resource_management.libraries.functions import conf_select from resource_management.libraries.functions import stack_tools from resource_management.libraries.functions.stack_select import get_stack_versions @@ -375,7 +375,7 @@ class InstallPackages(Script): retry_on_repo_unavailability=agent_stack_retry_on_unavailability, retry_count=agent_stack_retry_count ) - except Exception, err: + except Exception as err: ret_code = 1 Logger.logger.exception("Package Manager failed to install packages. Error: {0}".format(str(err))) @@ -392,16 +392,25 @@ class InstallPackages(Script): else: package_version_string = self.repository_version.replace('-', '_') package_version_string = package_version_string.replace('.', '_') + for package in new_packages_installed: if package_version_string and (package_version_string in package): Package(package, action="remove") + + if not verifyDependencies(): + ret_code = 1 + Logger.logger.error("Failure while verifying dependencies") + Logger.logger.error("*******************************************************************************") + Logger.logger.error("Manually verify and fix package dependencies and then re-run install_packages") + Logger.logger.error("*******************************************************************************") + # Compute the actual version in order to save it in structured out try: if ret_code == 0: self.compute_actual_version() else: self.check_partial_install() - except Fail, err: + except Fail as err: ret_code = 1 Logger.logger.exception("Failure while computing actual version. Error: {0}".format(str(err))) return ret_code
