]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Add OVS cleanup utility
authorGary Kotton <gkotton@redhat.com>
Tue, 18 Dec 2012 12:20:50 +0000 (12:20 +0000)
committerGary Kotton <gkotton@redhat.com>
Mon, 24 Dec 2012 13:32:11 +0000 (13:32 +0000)
Fixes bug 1091605

The utility should be called after rebooting an appliance. This
will purge the openvswicth of configured tap devices.

A configuration variable quantum_ports has been added. This is
by default True which indicates that only Quantum ports will be
deleted from the OVS. If this is set as False then all ports on the
bridge will be deleted.

Change-Id: I442f64cf82f95bfa99d7765eb09db1ce2ecf602e

bin/quantum-ovs-cleanup [new file with mode: 0755]
quantum/agent/linux/ovs_lib.py
quantum/agent/ovs_cleanup_util.py [new file with mode: 0644]
quantum/tests/unit/openvswitch/test_ovs_lib.py
quantum/tests/unit/test_agent_ovs_cleanup.py [new file with mode: 0644]
setup.py

diff --git a/bin/quantum-ovs-cleanup b/bin/quantum-ovs-cleanup
new file mode 100755 (executable)
index 0000000..096b8a7
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2012 Openstack, LLC.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import os
+import sys
+sys.path.insert(0, os.getcwd())
+
+from quantum.agent.ovs_cleanup_util import main
+
+
+main()
index 00f6586b028c29796c007a3d0dd85ba2a7d5a0fa..6e19602facb5607e2f829e43f85b7bda9cbf8122 100644 (file)
@@ -271,6 +271,15 @@ class OVSBridge:
             LOG.info(_("Unable to parse regex results. Exception: %s"), e)
             return
 
+    def delete_ports(self, all_ports=False):
+        if all_ports:
+            port_names = self.get_port_name_list()
+        else:
+            port_names = (port.port_name for port in self.get_vif_ports())
+
+        for port_name in port_names:
+            self.delete_port(port_name)
+
 
 def get_bridge_for_iface(root_helper, iface):
     args = ["ovs-vsctl", "--timeout=2", "iface-to-br", iface]
@@ -279,3 +288,12 @@ def get_bridge_for_iface(root_helper, iface):
     except Exception, e:
         LOG.error(_("iface %s not found. Exception: %s"), iface, e)
         return None
+
+
+def get_bridges(root_helper):
+    args = ["ovs-vsctl", "--timeout=2", "list-br"]
+    try:
+        return utils.execute(args, root_helper=root_helper).strip().split("\n")
+    except Exception, e:
+        LOG.error(_("Unable to retrieve bridges. Exception: %s"), e)
+        return []
diff --git a/quantum/agent/ovs_cleanup_util.py b/quantum/agent/ovs_cleanup_util.py
new file mode 100644 (file)
index 0000000..46bb3de
--- /dev/null
@@ -0,0 +1,75 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2012 OpenStack LLC.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import sys
+
+from quantum.agent import l3_agent
+from quantum.agent.linux import interface
+from quantum.agent.linux import ovs_lib
+from quantum.common import config
+from quantum.openstack.common import cfg
+from quantum.openstack.common import log as logging
+
+
+LOG = logging.getLogger(__name__)
+
+
+def setup_conf():
+    """Setup the cfg for the clean up utility.
+
+    Use separate setup_conf for the utility because there are many options
+    from the main config that do not apply during clean-up.
+    """
+    opts = [
+        cfg.BoolOpt('ovs_all_ports',
+                    default=False,
+                    help='True deletes all ports on the bridge. False deletes '
+                         'those created by Quantum.'),
+    ]
+
+    conf = cfg.CommonConfigOpts()
+    conf.register_opts(opts)
+    conf.register_opts(l3_agent.L3NATAgent.OPTS)
+    conf.register_opts(interface.OPTS)
+    config.setup_logging(conf)
+    return conf
+
+
+def main():
+    """Main method for cleaning up OVS bridges.
+
+    The utility cleans up the integration bridges used by Quantum.
+    """
+
+    conf = setup_conf()
+    conf(sys.argv)
+
+    configuration_bridges = set([conf.ovs_integration_bridge,
+                                 conf.external_network_bridge])
+    ovs_bridges = set(ovs_lib.get_bridges(conf.root_helper))
+
+    if conf.ovs_all_ports:
+        bridges = ovs_bridges
+    else:
+        bridges = configuration_bridges & ovs_bridges
+
+    for bridge in bridges:
+        LOG.info(_("Cleaning %s"), bridge)
+        ovs = ovs_lib.OVSBridge(bridge, conf.root_helper)
+        ovs.delete_ports(all_ports=conf.ovs_all_ports)
+
+    LOG.info(_("OVS cleanup completed successfully"))
index 52d8fbc73cc025228b81edec2d7d826b547d18f4..d84780da9d14427bd1ecbd89d8f3d7b57c9d6546 100644 (file)
@@ -313,3 +313,37 @@ class OVS_Lib_Test(unittest.TestCase):
         self.mox.ReplayAll()
         self.assertIsNone(ovs_lib.get_bridge_for_iface(root_helper, iface))
         self.mox.VerifyAll()
+
+    def test_delete_all_ports(self):
+        self.mox.StubOutWithMock(self.br, 'get_port_name_list')
+        self.br.get_port_name_list().AndReturn(['port1'])
+        self.mox.StubOutWithMock(self.br, 'delete_port')
+        self.br.delete_port('port1')
+        self.mox.ReplayAll()
+        self.br.delete_ports(all_ports=True)
+        self.mox.VerifyAll()
+
+    def test_delete_quantum_ports(self):
+        port1 = ovs_lib.VifPort('tap1234', 1, uuidutils.generate_uuid(),
+                                'ca:fe:de:ad:be:ef', 'br')
+        port2 = ovs_lib.VifPort('tap5678', 2, uuidutils.generate_uuid(),
+                                'ca:ee:de:ad:be:ef', 'br')
+        ports = [port1, port2]
+        self.mox.StubOutWithMock(self.br, 'get_vif_ports')
+        self.br.get_vif_ports().AndReturn([port1, port2])
+        self.mox.StubOutWithMock(self.br, 'delete_port')
+        self.br.delete_port('tap1234')
+        self.br.delete_port('tap5678')
+        self.mox.ReplayAll()
+        self.br.delete_ports(all_ports=False)
+        self.mox.VerifyAll()
+
+    def test_get_bridges(self):
+        bridges = ['br-int', 'br-ex']
+        root_helper = 'sudo'
+        utils.execute(["ovs-vsctl", self.TO, "list-br"],
+                      root_helper=root_helper).AndReturn('br-int\nbr-ex\n')
+
+        self.mox.ReplayAll()
+        self.assertEqual(ovs_lib.get_bridges(root_helper), bridges)
+        self.mox.VerifyAll()
diff --git a/quantum/tests/unit/test_agent_ovs_cleanup.py b/quantum/tests/unit/test_agent_ovs_cleanup.py
new file mode 100644 (file)
index 0000000..77a60cc
--- /dev/null
@@ -0,0 +1,43 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2012 OpenStack LLC.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import mock
+import unittest2 as unittest
+
+from quantum.agent.linux import ovs_lib
+from quantum.agent import ovs_cleanup_util as util
+from quantum.openstack.common import uuidutils
+
+
+class TestOVSCleanup(unittest.TestCase):
+    def test_setup_conf(self):
+        with mock.patch('quantum.common.config.setup_logging'):
+            conf = util.setup_conf()
+            self.assertEqual(conf.external_network_bridge, 'br-ex')
+            self.assertEqual(conf.ovs_integration_bridge, 'br-int')
+            self.assertFalse(conf.ovs_all_ports)
+
+    def test_main(self):
+        with mock.patch('quantum.common.config.setup_logging'):
+            br_patch = mock.patch('quantum.agent.linux.ovs_lib.get_bridges')
+            with br_patch as mock_get_bridges:
+                mock_get_bridges.return_value = ['br-int', 'br-ex']
+                with mock.patch(
+                    'quantum.agent.linux.ovs_lib.OVSBridge') as ovs:
+                    util.main()
+                    ovs.assert_has_calls([mock.call().delete_ports(
+                        all_ports=False)])
index dbcd405932dd21804cbdef11a065f114fbba5899..d9c23547c2bd0c05d52e0c3e629175e2b662e194 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -139,6 +139,7 @@ setuptools.setup(
             'quantum.plugins.nec.agent.nec_quantum_agent:main',
             'quantum-server = quantum.server:main',
             'quantum-debug = quantum.debug.shell:main',
+            'quantum-ovs-cleanup = quantum.agent.ovs_cleanup_util:main',
         ]
     },
 )