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/05cff453
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/05cff453
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/05cff453

Branch: refs/heads/branch-2.4
Commit: 05cff453bfeb27e0de8b94c164faf59e537d07eb
Parents: 8de7bbd
Author: Lisnichenko Dmitro <[email protected]>
Authored: Wed Jun 15 12:44:33 2016 +0300
Committer: Lisnichenko Dmitro <[email protected]>
Committed: Wed Jun 15 12:45:17 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/05cff453/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/05cff453/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/05cff453/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

Reply via email to