← Back to team overview

yellow team mailing list archive

[Merge] lp:~frankban/lpsetup/load-library into lp:lpsetup

 

Francesco Banconi has proposed merging lp:~frankban/lpsetup/load-library into lp:lpsetup.

Requested reviews:
  Launchpad Yellow Squad (yellow)

For more details, see:
https://code.launchpad.net/~frankban/lpsetup/load-library/+merge/105212

== Changes ==

Changed the way liblxc is loaded.
If the library is not found in /usr/lib/lxc/, it is searched inside /usr/lib/$DEB_HOST_MULTIARCH/lxc/ as suggested by Serge. This way lxc-ip is compatible with the new quantal version of lxc.
I don't have the environment variable $DEB_HOST_MULTIARCH in my system, but I've found that it is easily retrievable using dpkg-architecture, (see http://wiki.debian.org/Multiarch/Implementation).

== Tests ==


$ cd lplxcip/ && sudo nosetests -v
test_error (tests.test_helpers.ErrorTest) ... ok
test_host_multiarch_path (tests.test_helpers.LoadLibraryTest) ... ok
test_library_not_found (tests.test_helpers.LoadLibraryTest) ... ok
test_usual_path (tests.test_helpers.LoadLibraryTest) ... ok
test_output_of_all_interfaces (tests.test_helpers.OutputTest) ... ok
test_output_of_explicit_interface (tests.test_helpers.OutputTest) ... ok
test_redirection (tests.test_helpers.RedirectStderrTest) ... ok
test_as_root (tests.test_helpers.RootRequiredTest) ... ok
test_as_unprivileged_user (tests.test_helpers.RootRequiredTest) ... ok
test_failure (tests.test_helpers.WrapTest) ... ok
test_success (tests.test_helpers.WrapTest) ... ok
test_all_interfaces (tests.test_lxcip.GetInterfacesTest) ... ok
test_container_does_not_exist (tests.test_lxcip.GetInterfacesTest) ... ok
test_container_not_running (tests.test_lxcip.GetInterfacesTest) ... ok
test_exclude (tests.test_lxcip.GetInterfacesTest) ... ok
test_interfaces_not_found (tests.test_lxcip.GetInterfacesTest) ... ok
test_not_root (tests.test_lxcip.GetInterfacesTest) ... ok
test_invalid_interface (tests.test_lxcip.LXCIpTest) ... ok
test_invalid_name (tests.test_lxcip.LXCIpTest) ... ok
test_invalid_pid (tests.test_lxcip.LXCIpTest) ... ok
test_ip_address (tests.test_lxcip.LXCIpTest) ... ok
test_loopback (tests.test_lxcip.LXCIpTest) ... ok
test_multiple_interfaces (tests.test_lxcip.LXCIpTest) ... ok
test_not_root (tests.test_lxcip.LXCIpTest) ... ok
test_race_condition (tests.test_lxcip.LXCIpTest) ... ok
test_restart (tests.test_lxcip.LXCIpTest) ... ok
test_assertion (tests.test_utils.AssertOSErrorTest) ... ok
test_assertion_fails_different_exception (tests.test_utils.AssertOSErrorTest) ... ok
test_assertion_fails_different_message (tests.test_utils.AssertOSErrorTest) ... ok
test_assertion_fails_no_exception (tests.test_utils.AssertOSErrorTest) ... ok
test_create (tests.test_utils.LXCTest) ... ok
test_destroy (tests.test_utils.LXCTest) ... ok
test_start (tests.test_utils.LXCTest) ... ok
test_stop (tests.test_utils.LXCTest) ... ok
test_write_config (tests.test_utils.LXCTest) ... ok
test_mock (tests.test_utils.MockGeteuidTest) ... ok
test_failure (tests.test_utils.RetryTest) ... ok
test_success (tests.test_utils.RetryTest) ... ok
test_stopped (tests.test_utils.StoppedTest) ... ok
test_with_errors (tests.test_utils.StoppedTest) ... ok

----------------------------------------------------------------------
Ran 40 tests in 21.188s

OK

-- 
https://code.launchpad.net/~frankban/lpsetup/load-library/+merge/105212
Your team Launchpad Yellow Squad is requested to review the proposed merge of lp:~frankban/lpsetup/load-library into lp:lpsetup.
=== modified file 'lplxcip/lxcip.py'
--- lplxcip/lxcip.py	2012-05-07 13:25:53 +0000
+++ lplxcip/lxcip.py	2012-05-09 14:40:56 +0000
@@ -12,6 +12,7 @@
 import os
 import socket
 import struct
+import subprocess
 import sys
 
 
@@ -55,6 +56,33 @@
     return '\n'.join('{}: {}'.format(*i) for i in interface_ip_map)
 
 
+def _load_library(name, loader=None):
+    """Load a shared library into the process and return it.
+
+    Search the library `name` inside `/usr/lib` and, if *$DEB_HOST_MULTIARCH*
+    is retrievable, inside `/usr/lib/$DEB_HOST_MULTIARCH/`.
+
+    The optional argument `loader` is the callable used to load the library:
+    if None, `ctypes.cdll.LoadLibrary` is used.
+
+    Raise OSError if the library is not found.
+    """
+    if loader is None:
+        loader = ctypes.cdll.LoadLibrary
+    try:
+        return loader(os.path.join('/usr/lib/', name))
+    except OSError:
+        # Search the library in `/usr/lib/$DEB_HOST_MULTIARCH/`:
+        # see https://wiki.ubuntu.com/MultiarchSpec.
+        process = subprocess.Popen(
+            ['dpkg-architecture', '-qDEB_HOST_MULTIARCH'],
+            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        if not process.returncode:
+            output, _ = process.communicate()
+            return loader(os.path.join('/usr/lib/', output.strip(), name))
+        raise
+
+
 def _wrap(function, error_code):
     """Add error handling to the given C `function`.
 
@@ -142,7 +170,7 @@
     Raise OSError if LXC is not installed or the container is not found.
     """
     try:
-        liblxc = ctypes.cdll.LoadLibrary('/usr/lib/lxc/liblxc.so.0')
+        liblxc = _load_library('lxc/liblxc.so.0')
     except OSError:
         raise _error('not_installed')
     get_init_pid = _wrap(liblxc.get_init_pid, 'not_found')

=== modified file 'lplxcip/tests/test_helpers.py'
--- lplxcip/tests/test_helpers.py	2012-05-03 14:20:13 +0000
+++ lplxcip/tests/test_helpers.py	2012-05-09 14:40:56 +0000
@@ -5,6 +5,8 @@
 """Tests for the helpers functions in the lxcip module."""
 
 import ctypes
+import os
+import subprocess
 import tempfile
 import unittest
 
@@ -21,6 +23,41 @@
         self.assertIn(lxcip.ERRORS['not_found'], str(error))
 
 
+class LoadLibraryTest(unittest.TestCase):
+
+    library = 'library'
+
+    def multiarch_loader(self, path):
+        if path == os.path.join('/usr/lib/', self.library):
+            raise OSError
+        return path
+
+    def test_usual_path(self):
+        # Ensure a library residing under `/usr/lib/` is correctly loaded.
+        expected = os.path.join('/usr/lib/', self.library)
+        result = lxcip._load_library(self.library, loader=lambda path: path)
+        self.assertEqual(expected, result)
+
+    def test_host_multiarch_path(self):
+        # Ensure a library residing in `/usr/lib/$DEB_HOST_MULTIARCH/lxc/`
+        # is correctly loaded.
+        try:
+            output = subprocess.check_output(
+                ['dpkg-architecture', '-qDEB_HOST_MULTIARCH'],
+                stderr=subprocess.PIPE)
+        except subprocess.CalledProcessError:
+            self.skipTest('multiarch path not retrievable')
+        expected = os.path.join('/usr/lib/', output.strip(), self.library)
+        result = lxcip._load_library(
+            self.library, loader=self.multiarch_loader)
+        self.assertEqual(expected, result)
+
+    def test_library_not_found(self):
+        # Ensure an OSError is raised if the library is not found.
+        with self.assertRaises(OSError):
+            lxcip._load_library('__does_not_exist__')
+
+
 class OutputTest(unittest.TestCase):
 
     interfaces = ['eth0', 'lo']