]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Improve ovs_lib bridge management
authorMaru Newby <marun@redhat.com>
Mon, 9 Sep 2013 09:58:12 +0000 (09:58 +0000)
committerMaru Newby <marun@redhat.com>
Mon, 14 Oct 2013 21:56:11 +0000 (21:56 +0000)
Add the ability to add and remove bridges, check for bridge
existence, and lookup the bridge associated with a port.

This change is in support of functional testing for an ovsdb
monitor.

Partial-Bug: #1177973

Change-Id: I419923d8d77983997cd347fcf063b0bc367c0bbc

neutron/agent/linux/ovs_lib.py
neutron/tests/unit/openvswitch/test_ovs_lib.py

index 097630707aee0a41000cbb25fe58fb83129e96a5..6a4e7c652c39158f2f7428bc3b5d9c2dc4f6d16d 100644 (file)
@@ -44,10 +44,52 @@ class VifPort:
                 self.switch.br_name)
 
 
-class OVSBridge:
+class BaseOVS(object):
+
+    def __init__(self, root_helper):
+        self.root_helper = root_helper
+
+    def run_vsctl(self, args, check_error=False):
+        full_args = ["ovs-vsctl", "--timeout=2"] + args
+        try:
+            return utils.execute(full_args, root_helper=self.root_helper)
+        except Exception as e:
+            LOG.error(_("Unable to execute %(cmd)s. Exception: %(exception)s"),
+                      {'cmd': full_args, 'exception': e})
+            if check_error:
+                raise
+
+    def add_bridge(self, bridge_name):
+        self.run_vsctl(["--", "--may-exist", "add-br", bridge_name])
+        return OVSBridge(bridge_name, self.root_helper)
+
+    def delete_bridge(self, bridge_name):
+        self.run_vsctl(["--", "--if-exists", "del-br", bridge_name])
+
+    def bridge_exists(self, bridge_name):
+        try:
+            self.run_vsctl(['br-exists', bridge_name], check_error=True)
+        except RuntimeError as e:
+            if 'Exit code: 2\n' in str(e):
+                return False
+            raise
+        return True
+
+    def get_bridge_name_for_port_name(self, port_name):
+        try:
+            return self.run_vsctl(['port-to-br', port_name], check_error=True)
+        except RuntimeError as e:
+            if 'Exit code: 1\n' not in str(e):
+                raise
+
+    def port_exists(self, port_name):
+        return bool(self.get_bridge_name_for_port_name(port_name))
+
+
+class OVSBridge(BaseOVS):
     def __init__(self, br_name, root_helper):
+        super(OVSBridge, self).__init__(root_helper)
         self.br_name = br_name
-        self.root_helper = root_helper
         self.re_id = self.re_compile_id()
         self.defer_apply_flows = False
         self.deferred_flows = {'add': '', 'mod': '', 'del': ''}
@@ -65,17 +107,15 @@ class OVSBridge:
                                                'port': port})
         return re.compile(_re, re.M | re.X)
 
-    def run_vsctl(self, args):
-        full_args = ["ovs-vsctl", "--timeout=2"] + args
-        try:
-            return utils.execute(full_args, root_helper=self.root_helper)
-        except Exception as e:
-            LOG.error(_("Unable to execute %(cmd)s. Exception: %(exception)s"),
-                      {'cmd': full_args, 'exception': e})
+    def create(self):
+        self.add_bridge(self.br_name)
+
+    def destroy(self):
+        self.delete_bridge(self.br_name)
 
     def reset_bridge(self):
-        self.run_vsctl(["--", "--if-exists", "del-br", self.br_name])
-        self.run_vsctl(["add-br", self.br_name])
+        self.destroy()
+        self.create()
 
     def add_port(self, port_name):
         self.run_vsctl(["--", "--may-exist", "add-port", self.br_name,
index d4fef53e6ad96c450a83fb776a86432fbc4e2c60..415cd14a961a6256dcb106e9fa061b4437fdb04b 100644 (file)
@@ -26,6 +26,79 @@ from neutron.openstack.common import uuidutils
 from neutron.tests import base
 
 
+class TestBaseOVS(base.BaseTestCase):
+
+    def setUp(self):
+        super(TestBaseOVS, self).setUp()
+        self.root_helper = 'sudo'
+        self.ovs = ovs_lib.BaseOVS(self.root_helper)
+        self.br_name = 'bridge1'
+
+    def test_add_bridge(self):
+        with mock.patch.object(self.ovs, 'run_vsctl') as mock_vsctl:
+            bridge = self.ovs.add_bridge(self.br_name)
+
+        mock_vsctl.assert_called_with(["--", "--may-exist",
+                                       "add-br", self.br_name])
+        self.assertEqual(bridge.br_name, self.br_name)
+        self.assertEqual(bridge.root_helper, self.ovs.root_helper)
+
+    def test_delete_bridge(self):
+        with mock.patch.object(self.ovs, 'run_vsctl') as mock_vsctl:
+            self.ovs.delete_bridge(self.br_name)
+        mock_vsctl.assert_called_with(["--", "--if-exists", "del-br",
+                                       self.br_name])
+
+    def test_bridge_exists_returns_true(self):
+        with mock.patch.object(self.ovs, 'run_vsctl') as mock_vsctl:
+            self.assertTrue(self.ovs.bridge_exists(self.br_name))
+        mock_vsctl.assert_called_with(['br-exists', self.br_name],
+                                      check_error=True)
+
+    def test_bridge_exists_returns_false_for_exit_code_2(self):
+        with mock.patch.object(self.ovs, 'run_vsctl',
+                               side_effect=RuntimeError('Exit code: 2\n')):
+            self.assertFalse(self.ovs.bridge_exists('bridge1'))
+
+    def test_bridge_exists_raises_unknown_exception(self):
+        with mock.patch.object(self.ovs, 'run_vsctl',
+                               side_effect=RuntimeError()):
+            with testtools.ExpectedException(RuntimeError):
+                self.ovs.bridge_exists('bridge1')
+
+    def test_get_bridge_name_for_port_name_returns_bridge_for_valid_port(self):
+        port_name = 'bar'
+        with mock.patch.object(self.ovs, 'run_vsctl',
+                               return_value=self.br_name) as mock_vsctl:
+            bridge = self.ovs.get_bridge_name_for_port_name(port_name)
+        self.assertEqual(bridge, self.br_name)
+        mock_vsctl.assert_called_with(['port-to-br', port_name],
+                                      check_error=True)
+
+    def test_get_bridge_name_for_port_name_returns_none_for_exit_code_1(self):
+        with mock.patch.object(self.ovs, 'run_vsctl',
+                               side_effect=RuntimeError('Exit code: 1\n')):
+            self.assertFalse(self.ovs.get_bridge_name_for_port_name('bridge1'))
+
+    def test_get_bridge_name_for_port_name_raises_unknown_exception(self):
+        with mock.patch.object(self.ovs, 'run_vsctl',
+                               side_effect=RuntimeError()):
+            with testtools.ExpectedException(RuntimeError):
+                self.ovs.get_bridge_name_for_port_name('bridge1')
+
+    def _test_port_exists(self, br_name, result):
+        with mock.patch.object(self.ovs,
+                               'get_bridge_name_for_port_name',
+                               return_value=br_name):
+            self.assertEqual(self.ovs.port_exists('bar'), result)
+
+    def test_port_exists_returns_true_for_bridge_name(self):
+        self._test_port_exists(self.br_name, True)
+
+    def test_port_exists_returns_false_for_none(self):
+        self._test_port_exists(None, False)
+
+
 class OVS_Lib_Test(base.BaseTestCase):
     """A test suite to excercise the OVS libraries shared by Neutron agents.
 
@@ -66,12 +139,23 @@ class OVS_Lib_Test(base.BaseTestCase):
 
         self.mox.VerifyAll()
 
+    def test_create(self):
+        self.br.add_bridge(self.BR_NAME)
+        self.mox.ReplayAll()
+
+        self.br.create()
+        self.mox.VerifyAll()
+
+    def test_destroy(self):
+        self.br.delete_bridge(self.BR_NAME)
+        self.mox.ReplayAll()
+
+        self.br.destroy()
+        self.mox.VerifyAll()
+
     def test_reset_bridge(self):
-        utils.execute(["ovs-vsctl", self.TO, "--",
-                       "--if-exists", "del-br", self.BR_NAME],
-                      root_helper=self.root_helper)
-        utils.execute(["ovs-vsctl", self.TO, "add-br", self.BR_NAME],
-                      root_helper=self.root_helper)
+        self.br.destroy()
+        self.br.create()
         self.mox.ReplayAll()
 
         self.br.reset_bridge()