You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ao...@apache.org on 2015/06/03 17:09:35 UTC

ambari git commit: AMBARI-11657. Unable to install with non-root Agent (aonishuk)

Repository: ambari
Updated Branches:
  refs/heads/trunk 692c3a8c4 -> b549e35d4


AMBARI-11657. Unable to install with non-root Agent (aonishuk)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/b549e35d
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/b549e35d
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/b549e35d

Branch: refs/heads/trunk
Commit: b549e35d4dea2c57a4eb297faabb25d66f6a76fc
Parents: 692c3a8
Author: Andrew Onishuk <ao...@hortonworks.com>
Authored: Wed Jun 3 18:09:28 2015 +0300
Committer: Andrew Onishuk <ao...@hortonworks.com>
Committed: Wed Jun 3 18:09:28 2015 +0300

----------------------------------------------------------------------
 .../resource_management/TestPackageResource.py  | 32 +++++++++-----------
 .../core/providers/package/__init__.py          | 32 ++++++++++++++++++++
 .../core/providers/package/yumrpm.py            | 17 +++--------
 .../core/providers/package/zypper.py            | 14 +--------
 .../core/providers/system.py                    | 11 ++++++-
 .../core/resources/system.py                    |  1 +
 .../python/resource_management/core/shell.py    |  4 +++
 7 files changed, 67 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/b549e35d/ambari-agent/src/test/python/resource_management/TestPackageResource.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/resource_management/TestPackageResource.py b/ambari-agent/src/test/python/resource_management/TestPackageResource.py
index d69f278..c67745d 100644
--- a/ambari-agent/src/test/python/resource_management/TestPackageResource.py
+++ b/ambari-agent/src/test/python/resource_management/TestPackageResource.py
@@ -16,6 +16,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 '''
 
+import os
 import sys
 from unittest import TestCase
 from mock.mock import patch, MagicMock, call
@@ -27,6 +28,7 @@ from resource_management.core.resources import Package
 from resource_management.core import shell
 from resource_management.core.providers.package.apt import replace_underscores
 
+@patch.object(os, "geteuid", new=MagicMock(return_value=1234))
 class TestPackageResource(TestCase):
   @patch.object(shell, "call")
   @patch.object(shell, "checked_call")
@@ -87,23 +89,21 @@ class TestPackageResource(TestCase):
   @patch.object(shell, "checked_call")
   @patch.object(System, "os_family", new = 'redhat')
   def test_action_install_rhel(self, shell_mock):
-    sys.modules['yum'] = MagicMock()
-    sys.modules['yum'].YumBase.return_value = MagicMock()
-    sys.modules['yum'].YumBase.return_value.rpmdb = MagicMock()
-    sys.modules['yum'].YumBase.return_value.rpmdb.simplePkgList.return_value = [('some_packag',)]
+    sys.modules['rpm'] = MagicMock()
+    sys.modules['rpm'].TransactionSet.return_value = MagicMock()
+    sys.modules['rpm'].TransactionSet.return_value.dbMatch.return_value = [{'name':'some_packag'}]
     with Environment('/') as env:
       Package("some_package",
       )
-    self.assertTrue(sys.modules['yum'].YumBase.return_value.rpmdb.simplePkgList.called)
+    self.assertTrue(sys.modules['rpm'].TransactionSet.return_value.dbMatch.called)
     shell_mock.assert_called_with(['/usr/bin/yum', '-d', '0', '-e', '0', '-y', 'install', 'some_package'], logoutput=False, sudo=True)
 
   @patch.object(shell, "checked_call")
   @patch.object(System, "os_family", new = 'redhat')
   def test_action_install_pattern_rhel(self, shell_mock):
-    sys.modules['yum'] = MagicMock()
-    sys.modules['yum'].YumBase.return_value = MagicMock()
-    sys.modules['yum'].YumBase.return_value.rpmdb = MagicMock()
-    sys.modules['yum'].YumBase.return_value.rpmdb.simplePkgList.return_value = [('some_packag',)]
+    sys.modules['rpm'] = MagicMock()
+    sys.modules['rpm'].TransactionSet.return_value = MagicMock()
+    sys.modules['rpm'].TransactionSet.return_value.dbMatch.return_value = [{'name':'some_packag'}]
     with Environment('/') as env:
       Package("some_package*",
       )
@@ -159,10 +159,9 @@ class TestPackageResource(TestCase):
   @patch.object(shell, "checked_call")
   @patch.object(System, "os_family", new = 'redhat')
   def test_action_install_existent_rhel(self, shell_mock):
-    sys.modules['yum'] = MagicMock()
-    sys.modules['yum'].YumBase.return_value = MagicMock()
-    sys.modules['yum'].YumBase.return_value.rpmdb = MagicMock()
-    sys.modules['yum'].YumBase.return_value.rpmdb.simplePkgList.return_value = [('some_package',)]
+    sys.modules['rpm'] = MagicMock()
+    sys.modules['rpm'].TransactionSet.return_value = MagicMock()
+    sys.modules['rpm'].TransactionSet.return_value.dbMatch.return_value = [{'name':'some_package'}]
     with Environment('/') as env:
       Package("some_package",
               )
@@ -196,10 +195,9 @@ class TestPackageResource(TestCase):
   @patch.object(shell, "checked_call")
   @patch.object(System, "os_family", new = 'redhat')
   def test_action_remove_rhel(self, shell_mock):
-    sys.modules['yum'] = MagicMock()
-    sys.modules['yum'].YumBase.return_value = MagicMock()
-    sys.modules['yum'].YumBase.return_value.rpmdb = MagicMock()
-    sys.modules['yum'].YumBase.return_value.rpmdb.simplePkgList.return_value = [('some_package',)]
+    sys.modules['rpm'] = MagicMock()
+    sys.modules['rpm'].TransactionSet.return_value = MagicMock()
+    sys.modules['rpm'].TransactionSet.return_value.dbMatch.return_value = [{'name':'some_package'}]
     with Environment('/') as env:
       Package("some_package",
               action = "remove"

http://git-wip-us.apache.org/repos/asf/ambari/blob/b549e35d/ambari-common/src/main/python/resource_management/core/providers/package/__init__.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/resource_management/core/providers/package/__init__.py b/ambari-common/src/main/python/resource_management/core/providers/package/__init__.py
index 2358e86..ad48b43 100644
--- a/ambari-common/src/main/python/resource_management/core/providers/package/__init__.py
+++ b/ambari-common/src/main/python/resource_management/core/providers/package/__init__.py
@@ -20,11 +20,13 @@ Ambari Agent
 
 """
 
+import re
 import logging
 
 from resource_management.core.base import Fail
 from resource_management.core.providers import Provider
 from resource_management.core.logger import Logger
+from resource_management.core.utils import suppress_stdout
 
 
 class PackageProvider(Provider):
@@ -59,4 +61,34 @@ class PackageProvider(Provider):
   def get_logoutput(self):
     return self.resource.logoutput==True and Logger.logger.isEnabledFor(logging.INFO) or self.resource.logoutput==None and Logger.logger.isEnabledFor(logging.DEBUG)
     
+  def yum_check_package_available(self, name):
+    """
+    Does the same as rpm_check_package_avaiable, but faster.
+    However need root permissions.
+    """
+    import yum # Python Yum API is much faster then other check methods. (even then "import rpm")
+    yb = yum.YumBase()
+    name_regex = re.escape(name).replace("\\?", ".").replace("\\*", ".*") + '$'
+    regex = re.compile(name_regex)
     
+    with suppress_stdout():
+      package_list = yb.rpmdb.simplePkgList()
+    
+    for package in package_list:
+      if regex.match(package[0]):
+        return True
+    
+    return False
+  
+  def rpm_check_package_available(self, name):
+    import rpm # this is faster then calling 'rpm'-binary externally.
+    ts = rpm.TransactionSet()
+    packages = ts.dbMatch()
+    
+    name_regex = re.escape(name).replace("\\?", ".").replace("\\*", ".*") + '$'
+    regex = re.compile(name_regex)
+    
+    for package in packages:
+      if regex.match(package['name']):
+        return True
+    return False

http://git-wip-us.apache.org/repos/asf/ambari/blob/b549e35d/ambari-common/src/main/python/resource_management/core/providers/package/yumrpm.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/resource_management/core/providers/package/yumrpm.py b/ambari-common/src/main/python/resource_management/core/providers/package/yumrpm.py
index 2d39c4d..c17b7f0 100644
--- a/ambari-common/src/main/python/resource_management/core/providers/package/yumrpm.py
+++ b/ambari-common/src/main/python/resource_management/core/providers/package/yumrpm.py
@@ -26,7 +26,6 @@ from resource_management.core.shell import string_cmd_from_args_list
 from resource_management.core.logger import Logger
 from resource_management.core.utils import suppress_stdout
 import os
-import re
 
 INSTALL_CMD = {
   True: ['/usr/bin/yum', '-y', 'install'],
@@ -81,16 +80,8 @@ class YumProvider(PackageProvider):
     yum in inconsistant state (locked, used, having invalid repo). Once packages are installed
     we should not rely on that.
     """
-    import yum # Python Yum API is much faster then other check methods. (even then "import rpm")
-    yb = yum.YumBase()
-    name_regex = re.escape(name).replace("\\?", ".").replace("\\*", ".*") + '$'
-    regex = re.compile(name_regex)
-    
-    with suppress_stdout():
-      package_list = yb.rpmdb.simplePkgList()
-    
-    for package in package_list:
-      if regex.match(package[0]):
-        return True
+    if os.geteuid() == 0: 
+      return self.yum_check_package_available(name)
+    else:
+      return self.rpm_check_package_available(name)
     
-    return False
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b549e35d/ambari-common/src/main/python/resource_management/core/providers/package/zypper.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/resource_management/core/providers/package/zypper.py b/ambari-common/src/main/python/resource_management/core/providers/package/zypper.py
index b7f33f4..dd16ce0 100644
--- a/ambari-common/src/main/python/resource_management/core/providers/package/zypper.py
+++ b/ambari-common/src/main/python/resource_management/core/providers/package/zypper.py
@@ -26,8 +26,6 @@ from resource_management.core.shell import string_cmd_from_args_list
 from resource_management.core.logger import Logger
 from resource_management.core.utils import suppress_stdout
 
-import re
-
 INSTALL_CMD = {
   True: ['/usr/bin/zypper', 'install', '--auto-agree-with-licenses', '--no-confirm'],
   False: ['/usr/bin/zypper', '--quiet', 'install', '--auto-agree-with-licenses', '--no-confirm'],
@@ -102,14 +100,4 @@ class ZypperProvider(PackageProvider):
     zypper in inconsistant state (locked, used, having invalid repo). Once packages are installed
     we should not rely on that.
     """
-    import rpm # this is faster then calling 'rpm'-binary externally.
-    ts = rpm.TransactionSet()
-    packages = ts.dbMatch()
-    
-    name_regex = re.escape(name).replace("\\?", ".").replace("\\*", ".*") + '$'
-    regex = re.compile(name_regex)
-    
-    for package in packages:
-      if regex.match(package['name']):
-        return True
-    return False
+    return self.rpm_check_package_available(name)

http://git-wip-us.apache.org/repos/asf/ambari/blob/b549e35d/ambari-common/src/main/python/resource_management/core/providers/system.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/resource_management/core/providers/system.py b/ambari-common/src/main/python/resource_management/core/providers/system.py
index 43044db..3a1b218 100644
--- a/ambari-common/src/main/python/resource_management/core/providers/system.py
+++ b/ambari-common/src/main/python/resource_management/core/providers/system.py
@@ -131,9 +131,18 @@ class FileProvider(Provider):
 class DirectoryProvider(Provider):
   def action_create(self):
     path = self.resource.path
-
+    
     if not sudo.path_exists(path):
       Logger.info("Creating directory %s" % self.resource)
+      
+      # dead links should be followed, else we gonna have failures on trying to create directories on top of them.
+      if self.resource.follow:
+        while sudo.path_lexists(path):
+          path = sudo.readlink(path)
+          
+        if path != self.resource.path:
+          Logger.info("Following the link {0} to {1} to create the directory".format(self.resource.path, path))
+      
       if self.resource.recursive:
         if self.resource.recursive_permission:
           DirectoryProvider.makedirs_and_set_permission_recursively(path, self.resource.owner,

http://git-wip-us.apache.org/repos/asf/ambari/blob/b549e35d/ambari-common/src/main/python/resource_management/core/resources/system.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/resource_management/core/resources/system.py b/ambari-common/src/main/python/resource_management/core/resources/system.py
index bf10c43..1f00da1 100644
--- a/ambari-common/src/main/python/resource_management/core/resources/system.py
+++ b/ambari-common/src/main/python/resource_management/core/resources/system.py
@@ -57,6 +57,7 @@ class Directory(Resource):
   mode = ResourceArgument()
   owner = ResourceArgument()
   group = ResourceArgument()
+  follow = BooleanArgument(default=True) # follow links?
   recursive = BooleanArgument(default=False) # this work for 'create', 'delete' is anyway recursive
   recursive_permission = BooleanArgument(default=False) # sets given perms to all non-existent folders which are created recursively
   """

http://git-wip-us.apache.org/repos/asf/ambari/blob/b549e35d/ambari-common/src/main/python/resource_management/core/shell.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/resource_management/core/shell.py b/ambari-common/src/main/python/resource_management/core/shell.py
index 2ddc9eb..2e5a1b0 100644
--- a/ambari-common/src/main/python/resource_management/core/shell.py
+++ b/ambari-common/src/main/python/resource_management/core/shell.py
@@ -236,6 +236,10 @@ def as_user(command, user, env=None, auto_escape=True):
 def quote_bash_args(command):
   if not command:
     return "''"
+  
+  if not isinstance(command, basestring):
+    raise Fail("Command should be a list of strings, found '{0}' in command list elements".format(str(command)))
+  
   valid = set(string.ascii_letters + string.digits + '@%_-+=:,./')
   for char in command:
     if char not in valid: