From ba72f9c7358850e8d4c5339c329094f08eb0204d Mon Sep 17 00:00:00 2001 From: Gary Kotton Date: Tue, 24 Apr 2012 02:02:03 -0400 Subject: [PATCH] The fixes enable the OVS and linuxbridge agenets to "keep alive" when the host running the server/plugin is down. bugs 985470 and 985646 Change-Id: Ia7174c80a0760d27fe36fb6e7764e3abe32ae8a6 --- .../plugins/linuxbridge/linuxbridge_conf.ini | 6 +- .../openvswitch/ovs_quantum_plugin.ini | 4 + .../agent/linuxbridge_quantum_agent.py | 192 ++++++++------ .../tests/unit/_test_linuxbridgeAgent.py | 241 +++++++++--------- .../openvswitch/agent/ovs_quantum_agent.py | 220 ++++++++++------ .../openvswitch/tests/unit/test_tunnel.py | 14 +- 6 files changed, 385 insertions(+), 292 deletions(-) diff --git a/etc/quantum/plugins/linuxbridge/linuxbridge_conf.ini b/etc/quantum/plugins/linuxbridge/linuxbridge_conf.ini index dd25e07866..93b66d4d74 100644 --- a/etc/quantum/plugins/linuxbridge/linuxbridge_conf.ini +++ b/etc/quantum/plugins/linuxbridge/linuxbridge_conf.ini @@ -16,12 +16,14 @@ host = port = 3306 [LINUX_BRIDGE] -#this is the interface connected to the switch on your Quantum network +# This is the interface connected to the switch on your Quantum network physical_interface = eth1 [AGENT] -#agent's polling interval in seconds +# Agent's polling interval in seconds polling_interval = 2 +# Agent's database reconnection interval in seconds - in event connectivity is lost +reconnect_interval = 2 # Change to "sudo quantum-rootwrap" to limit commands that can be run # as root. root_helper = sudo diff --git a/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini b/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini index a7a7f1a6ba..12796aa0c5 100644 --- a/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini +++ b/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini @@ -32,6 +32,10 @@ integration-bridge = br-int # local-ip = 10.0.0.3 [AGENT] +# Agent's polling interval in seconds +polling_interval = 2 +# Agent's database reconnection interval in seconds - in event connectivity is lost +reconnect_interval = 2 # Change to "sudo quantum-rootwrap" to limit commands that can be run # as root. root_helper = sudo diff --git a/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py b/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py index 45cd2b62db..0c1a896df0 100755 --- a/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py +++ b/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py @@ -21,21 +21,22 @@ # Based on the structure of the OpenVSwitch agent in the # Quantum OpenVSwitch Plugin. # @author: Sumit Naiksatam, Cisco Systems, Inc. -# - -from optparse import OptionParser -from subprocess import * import ConfigParser -import logging as LOG -import MySQLdb +import logging +from optparse import OptionParser import os import shlex import signal -import sqlite3 +import subprocess import sys import time +from sqlalchemy.ext.sqlsoup import SqlSoup + +logging.basicConfig() +LOG = logging.getLogger(__name__) + BRIDGE_NAME_PREFIX = "brq" GATEWAY_INTERFACE_PREFIX = "gw-" @@ -50,7 +51,9 @@ VLAN_BINDINGS = "vlan_bindings" PORT_BINDINGS = "port_bindings" OP_STATUS_UP = "UP" OP_STATUS_DOWN = "DOWN" -DB_CONNECTION = None +# Default inteval values +DEFAULT_POLLING_INTERVAL = 2 +DEFAULT_RECONNECT_INTERVAL = 2 class LinuxBridge: @@ -62,7 +65,7 @@ class LinuxBridge: def run_cmd(self, args): cmd = shlex.split(self.root_helper) + args LOG.debug("Running command: " + " ".join(cmd)) - p = Popen(cmd, stdout=PIPE) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) retval = p.communicate()[0] if p.returncode == -(signal.SIGALRM): LOG.debug("Timeout running command: " + " ".join(cmd)) @@ -81,7 +84,7 @@ class LinuxBridge: def get_bridge_name(self, network_id): if not network_id: LOG.warning("Invalid Network ID, will lead to incorrect bridge" \ - "name") + "name") bridge_name = self.br_name_prefix + network_id[0:11] return bridge_name @@ -95,7 +98,7 @@ class LinuxBridge: def get_tap_device_name(self, interface_id): if not interface_id: LOG.warning("Invalid Interface ID, will lead to incorrect " \ - "tap device name") + "tap device name") tap_device_name = TAP_INTERFACE_PREFIX + interface_id[0:11] return tap_device_name @@ -109,9 +112,8 @@ class LinuxBridge: def get_interfaces_on_bridge(self, bridge_name): if self.device_exists(bridge_name): - bridge_interface_path = \ - BRIDGE_INTERFACES_FS.replace(BRIDGE_NAME_PLACEHOLDER, - bridge_name) + bridge_interface_path = BRIDGE_INTERFACES_FS.replace( + BRIDGE_NAME_PLACEHOLDER, bridge_name) return os.listdir(bridge_interface_path) def get_all_tap_devices(self): @@ -149,9 +151,8 @@ class LinuxBridge: if not device_name: return False else: - bridge_port_path = \ - BRIDGE_PORT_FS_FOR_DEVICE.replace(DEVICE_NAME_PLACEHOLDER, - device_name) + bridge_port_path = BRIDGE_PORT_FS_FOR_DEVICE.replace( + DEVICE_NAME_PLACEHOLDER, device_name) return os.path.exists(bridge_port_path) def ensure_vlan_bridge(self, network_id, vlan_id): @@ -183,7 +184,7 @@ class LinuxBridge: """ if not self.device_exists(bridge_name): LOG.debug("Starting bridge %s for subinterface %s" % (bridge_name, - interface)) + interface)) if self.run_cmd(['brctl', 'addbr', bridge_name]): return if self.run_cmd(['brctl', 'setfd', bridge_name, str(0)]): @@ -210,8 +211,7 @@ class LinuxBridge: tap_device_name) return False - current_bridge_name = \ - self.get_bridge_for_tap_device(tap_device_name) + current_bridge_name = self.get_bridge_for_tap_device(tap_device_name) bridge_name = self.get_bridge_name(network_id) if bridge_name == current_bridge_name: return False @@ -237,12 +237,10 @@ class LinuxBridge: """ return False if interface_id.startswith(GATEWAY_INTERFACE_PREFIX): - return self.add_tap_interface(network_id, vlan_id, - interface_id) + return self.add_tap_interface(network_id, vlan_id, interface_id) else: tap_device_name = self.get_tap_device_name(interface_id) - return self.add_tap_interface(network_id, vlan_id, - tap_device_name) + return self.add_tap_interface(network_id, vlan_id, tap_device_name) def delete_vlan_bridge(self, bridge_name): if self.device_exists(bridge_name): @@ -266,15 +264,15 @@ class LinuxBridge: if self.device_exists(bridge_name): if not self.is_device_on_bridge(interface_name): return True - LOG.debug("Removing device %s from bridge %s" % \ + LOG.debug("Removing device %s from bridge %s" % (interface_name, bridge_name)) if self.run_cmd(['brctl', 'delif', bridge_name, interface_name]): return False - LOG.debug("Done removing device %s from bridge %s" % \ + LOG.debug("Done removing device %s from bridge %s" % (interface_name, bridge_name)) return True else: - LOG.debug("Cannot remove device %s, bridge %s does not exist" % \ + LOG.debug("Cannot remove device %s, bridge %s does not exist" % (interface_name, bridge_name)) return False @@ -291,10 +289,12 @@ class LinuxBridge: class LinuxBridgeQuantumAgent: def __init__(self, br_name_prefix, physical_interface, polling_interval, - root_helper): - self.polling_interval = int(polling_interval) + reconnect_interval, root_helper): + self.polling_interval = polling_interval + self.reconnect_interval = reconnect_interval self.root_helper = root_helper self.setup_linux_bridge(br_name_prefix, physical_interface) + self.db_connected = False def setup_linux_bridge(self, br_name_prefix, physical_interface): self.linux_br = LinuxBridge(br_name_prefix, physical_interface, @@ -327,16 +327,16 @@ class LinuxBridgeQuantumAgent: LOG.debug("plugged tap device names %s" % plugged_tap_device_names) for tap_device in self.linux_br.get_all_tap_devices(): if tap_device not in plugged_tap_device_names: - current_bridge_name = \ - self.linux_br.get_bridge_for_tap_device(tap_device) + current_bridge_name = ( + self.linux_br.get_bridge_for_tap_device(tap_device)) if current_bridge_name: self.linux_br.remove_interface(current_bridge_name, tap_device) for gw_device in self.linux_br.get_all_gateway_devices(): if gw_device not in plugged_gateway_device_names: - current_bridge_name = \ - self.linux_br.get_bridge_for_tap_device(gw_device) + current_bridge_name = ( + self.linux_br.get_bridge_for_tap_device(gw_device)) if current_bridge_name: self.linux_br.remove_interface(current_bridge_name, gw_device) @@ -353,42 +353,53 @@ class LinuxBridgeQuantumAgent: if bridge not in current_quantum_bridge_names: self.linux_br.delete_vlan_bridge(bridge) - def manage_networks_on_host(self, conn, old_vlan_bindings, + def manage_networks_on_host(self, db, + old_vlan_bindings, old_port_bindings): - if DB_CONNECTION != 'sqlite': - cursor = MySQLdb.cursors.DictCursor(conn) - else: - cursor = conn.cursor() - cursor.execute("SELECT * FROM vlan_bindings") - rows = cursor.fetchall() - cursor.close() vlan_bindings = {} + try: + vlan_binds = db.vlan_bindings.all() + except Exception as e: + LOG.info("Unable to get vlan bindings! Exception: %s" % e) + self.db_connected = False + return {VLAN_BINDINGS: {}, + PORT_BINDINGS: []} + vlans_string = "" - for row in rows: - vlan_bindings[row['network_id']] = row - vlans_string = "%s %s" % (vlans_string, row) + for bind in vlan_binds: + entry = {'network_id': bind.network_id, 'vlan_id': bind.vlan_id} + vlan_bindings[bind.network_id] = entry + vlans_string = "%s %s" % (vlans_string, entry) + + port_bindings = [] + try: + port_binds = db.ports.all() + except Exception as e: + LOG.info("Unable to get port bindings! Exception: %s" % e) + self.db_connected = False + return {VLAN_BINDINGS: {}, + PORT_BINDINGS: []} + + all_bindings = {} + for bind in port_binds: + all_bindings[bind.uuid] = bind + entry = {'network_id': bind.network_id, 'state': bind.state, + 'op_status': bind.op_status, 'uuid': bind.uuid, + 'interface_id': bind.interface_id} + if bind.state == 'ACTIVE': + port_bindings.append(entry) plugged_interfaces = [] - cursor = MySQLdb.cursors.DictCursor(conn) - cursor.execute("SELECT * FROM ports where state = 'ACTIVE'") - port_bindings = cursor.fetchall() - cursor.close() - ports_string = "" for pb in port_bindings: ports_string = "%s %s" % (ports_string, pb) if pb['interface_id']: - vlan_id = \ - str(vlan_bindings[pb['network_id']]['vlan_id']) + vlan_id = str(vlan_bindings[pb['network_id']]['vlan_id']) if self.process_port_binding(pb['uuid'], pb['network_id'], pb['interface_id'], vlan_id): - cursor = MySQLdb.cursors.DictCursor(conn) - sql = PORT_OPSTATUS_UPDATESQL % (pb['uuid'], - OP_STATUS_UP) - cursor.execute(sql) - cursor.close() + all_bindings[pb['uuid']].op_status = OP_STATUS_UP plugged_interfaces.append(pb['interface_id']) if old_port_bindings != port_bindings: @@ -401,16 +412,30 @@ class LinuxBridgeQuantumAgent: self.process_deleted_networks(vlan_bindings) - conn.commit() + try: + db.commit() + except Exception as e: + LOG.info("Unable to update database! Exception: %s" % e) + db.rollback() + vlan_bindings = {} + port_bindings = [] + return {VLAN_BINDINGS: vlan_bindings, PORT_BINDINGS: port_bindings} - def daemon_loop(self, conn): + def daemon_loop(self, db_connection_url): old_vlan_bindings = {} - old_port_bindings = {} + old_port_bindings = [] + self.db_connected = False while True: - bindings = self.manage_networks_on_host(conn, + if not self.db_connected: + time.sleep(self.reconnect_interval) + db = SqlSoup(db_connection_url) + self.db_connected = True + LOG.info("Connecting to database \"%s\" on %s" % + (db.engine.url.database, db.engine.url.host)) + bindings = self.manage_networks_on_host(db, old_vlan_bindings, old_port_bindings) old_vlan_bindings = bindings[VLAN_BINDINGS] @@ -427,9 +452,9 @@ def main(): options, args = parser.parse_args() if options.verbose: - LOG.basicConfig(level=LOG.DEBUG) + LOG.setLevel(logging.DEBUG) else: - LOG.basicConfig(level=LOG.WARN) + LOG.setLevel(logging.WARNING) if len(args) != 1: parser.print_help() @@ -437,22 +462,28 @@ def main(): config_file = args[0] config = ConfigParser.ConfigParser() - conn = None try: fh = open(config_file) fh.close() config.read(config_file) br_name_prefix = BRIDGE_NAME_PREFIX physical_interface = config.get("LINUX_BRIDGE", "physical_interface") - polling_interval = config.get("AGENT", "polling_interval") + if config.has_option("AGENT", "polling_interval"): + polling_interval = config.getint("AGENT", "polling_interval") + else: + polling_interval = DEFAULT_POLLING_INTERVAL + LOG.info("Polling interval not defined. Using default.") + if config.has_option("AGENT", "reconnect_interval"): + reconnect_interval = config.getint("AGENT", "reconnect_interval") + else: + reconnect_interval = DEFAULT_RECONNECT_INTERVAL + LOG.info("Reconnect interval not defined. Using default.") root_helper = config.get("AGENT", "root_helper") 'Establish database connection and load models' - global DB_CONNECTION - DB_CONNECTION = config.get("DATABASE", "connection") - if DB_CONNECTION == 'sqlite': + connection = config.get("DATABASE", "connection") + if connection == 'sqlite': LOG.info("Connecting to sqlite DB") - conn = sqlite3.connect(":memory:") - conn.row_factory = sqlite3.Row + db_connection_url = "sqlite:///:memory:" else: db_name = config.get("DATABASE", "name") db_user = config.get("DATABASE", "user") @@ -460,21 +491,18 @@ def main(): db_host = config.get("DATABASE", "host") db_port = int(config.get("DATABASE", "port")) LOG.info("Connecting to database %s on %s" % (db_name, db_host)) - conn = MySQLdb.connect(host=db_host, user=db_user, port=db_port, - passwd=db_pass, db=db_name) - except Exception, e: - LOG.error("Unable to parse config file \"%s\": \nException%s" - % (config_file, str(e))) + db_connection_url = ("%s://%s:%s@%s:%d/%s" % + (connection, db_user, db_pass, db_host, db_port, db_name)) + except Exception as e: + LOG.error("Unable to parse config file \"%s\": \nException %s" % + (config_file, str(e))) sys.exit(1) - try: - plugin = LinuxBridgeQuantumAgent(br_name_prefix, physical_interface, - polling_interval, root_helper) - LOG.info("Agent initialized successfully, now running...") - plugin.daemon_loop(conn) - finally: - if conn: - conn.close() + plugin = LinuxBridgeQuantumAgent(br_name_prefix, physical_interface, + polling_interval, reconnect_interval, + root_helper) + LOG.info("Agent initialized successfully, now running... ") + plugin.daemon_loop(db_connection_url) sys.exit(0) diff --git a/quantum/plugins/linuxbridge/tests/unit/_test_linuxbridgeAgent.py b/quantum/plugins/linuxbridge/tests/unit/_test_linuxbridgeAgent.py index 09d30bf8d7..21b142acb2 100644 --- a/quantum/plugins/linuxbridge/tests/unit/_test_linuxbridgeAgent.py +++ b/quantum/plugins/linuxbridge/tests/unit/_test_linuxbridgeAgent.py @@ -15,43 +15,43 @@ # under the License. # # @author: Shweta Padubidri, Cisco Systems, Inc. -# import ConfigParser -import logging as LOG -import unittest -import sys +import logging import os import shlex import signal -from subprocess import * +import subprocess +import sys +import unittest -import quantum.plugins.linuxbridge.agent.linuxbridge_quantum_agent\ - as linux_agent -from quantum.plugins.linuxbridge.common import constants as lconst -from quantum.plugins.linuxbridge import LinuxBridgePlugin -from quantum.plugins.linuxbridge.db import l2network_db as cdb import quantum.db.api as db +from quantum.plugins.linuxbridge import LinuxBridgePlugin +from quantum.plugins.linuxbridge.agent import ( + linuxbridge_quantum_agent as linux_agent, + ) +from quantum.plugins.linuxbridge.common import constants as lconst +from quantum.plugins.linuxbridge.db import l2network_db as cdb -LOG.getLogger(__name__) +LOG = logging.getLogger(__name__) class LinuxBridgeAgentTest(unittest.TestCase): def test_add_gateway_interface( - self, tenant_id="test_tenant", network_name="test_network", - interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc', - mac_address='fe:16:3e:51:60:dd'): + self, tenant_id="test_tenant", network_name="test_network", + interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc', + mac_address='fe:16:3e:51:60:dd'): LOG.debug("test_tap_gateway_interface - START") - new_network =\ - self._linuxbridge_plugin.create_network(tenant_id, network_name) + new_network = ( + self._linuxbridge_plugin.create_network(tenant_id, network_name)) new_port = self._linuxbridge_plugin.create_port( - tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) + tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) self._linuxbridge_plugin.plug_interface( - tenant_id, new_network[lconst.NET_ID], - new_port[lconst.PORT_ID], interface_id) + tenant_id, new_network[lconst.NET_ID], + new_port[lconst.PORT_ID], interface_id) bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11] self.create_bridge(bridge_name) device_name = self.gw_name_prefix + new_network[lconst.NET_ID][0:11] @@ -61,15 +61,15 @@ class LinuxBridgeAgentTest(unittest.TestCase): vlan_id = vlan_bind[lconst.VLANID] self._linuxbridge_quantum_agent.process_port_binding( - new_port[lconst.PORT_ID], new_network[lconst.NET_ID], - device_name, str(vlan_id)) - list_interface = self._linuxbridge_quantum_agent.linux_br.\ - get_interfaces_on_bridge(bridge_name) + new_port[lconst.PORT_ID], new_network[lconst.NET_ID], + device_name, str(vlan_id)) + list_interface = (self._linuxbridge_quantum_agent.linux_br. + get_interfaces_on_bridge(bridge_name)) self.assertTrue(device_name in list_interface) for interface in list_interface: self._linuxbridge_quantum_agent.linux_br.remove_interface( - bridge_name, interface) + bridge_name, interface) self.delete_device(interface) self.delete_bridge(bridge_name) self.tearDownUnplugInterface(tenant_id, new_network[lconst.NET_ID], @@ -78,18 +78,18 @@ class LinuxBridgeAgentTest(unittest.TestCase): LOG.debug("test_add_gateway_interface - END") def test_add_tap_interface( - self, tenant_id="test_tenant", network_name="test_network", - interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc', - mac_address='fe:16:3e:51:60:dd'): + self, tenant_id="test_tenant", network_name="test_network", + interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc', + mac_address='fe:16:3e:51:60:dd'): LOG.debug("test_add_tap_interface - START") - new_network =\ - self._linuxbridge_plugin.create_network(tenant_id, network_name) + new_network = ( + self._linuxbridge_plugin.create_network(tenant_id, network_name)) new_port = self._linuxbridge_plugin.create_port( - tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) + tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) self._linuxbridge_plugin.plug_interface( - tenant_id, new_network[lconst.NET_ID], - new_port[lconst.PORT_ID], interface_id) + tenant_id, new_network[lconst.NET_ID], + new_port[lconst.PORT_ID], interface_id) bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11] self.create_bridge(bridge_name) device_name = self.tap_name_prefix + interface_id[0:11] @@ -99,15 +99,15 @@ class LinuxBridgeAgentTest(unittest.TestCase): vlan_id = vlan_bind[lconst.VLANID] self._linuxbridge_quantum_agent.process_port_binding( - new_port[lconst.PORT_ID], new_network[lconst.NET_ID], - interface_id, str(vlan_id)) - list_interface = self._linuxbridge_quantum_agent.linux_br.\ - get_interfaces_on_bridge(bridge_name) + new_port[lconst.PORT_ID], new_network[lconst.NET_ID], + interface_id, str(vlan_id)) + list_interface = (self._linuxbridge_quantum_agent.linux_br. + get_interfaces_on_bridge(bridge_name)) self.assertTrue(device_name in list_interface) for interface in list_interface: self._linuxbridge_quantum_agent.linux_br.remove_interface( - bridge_name, interface) + bridge_name, interface) self.delete_device(interface) self.delete_bridge(bridge_name) self.tearDownUnplugInterface(tenant_id, new_network[lconst.NET_ID], @@ -121,13 +121,13 @@ class LinuxBridgeAgentTest(unittest.TestCase): mac_address='fe:16:3e:51:60:dd'): LOG.debug("test_remove_interface - START") - new_network =\ - self._linuxbridge_plugin.create_network(tenant_id, network_name) + new_network = ( + self._linuxbridge_plugin.create_network(tenant_id, network_name)) new_port = self._linuxbridge_plugin.create_port( - tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) + tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) self._linuxbridge_plugin.plug_interface( - tenant_id, new_network[lconst.NET_ID], - new_port[lconst.PORT_ID], interface_id) + tenant_id, new_network[lconst.NET_ID], + new_port[lconst.PORT_ID], interface_id) bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11] self.create_bridge(bridge_name) device_name = self.tap_name_prefix + interface_id[0:11] @@ -137,19 +137,19 @@ class LinuxBridgeAgentTest(unittest.TestCase): vlan_id = vlan_bind[lconst.VLANID] self._linuxbridge_quantum_agent.process_port_binding( - new_port[lconst.PORT_ID], new_network[lconst.NET_ID], - interface_id, str(vlan_id)) - list_interface = self._linuxbridge_quantum_agent.linux_br.\ - get_interfaces_on_bridge(bridge_name) + new_port[lconst.PORT_ID], new_network[lconst.NET_ID], + interface_id, str(vlan_id)) + list_interface = (self._linuxbridge_quantum_agent.linux_br. + get_interfaces_on_bridge(bridge_name)) self._linuxbridge_quantum_agent.linux_br.remove_interface(bridge_name, - device_name) - list_interface = self._linuxbridge_quantum_agent.linux_br.\ - get_interfaces_on_bridge(bridge_name) + device_name) + list_interface = (self._linuxbridge_quantum_agent.linux_br. + get_interfaces_on_bridge(bridge_name)) self.assertFalse(device_name in list_interface) for interface in list_interface: self._linuxbridge_quantum_agent.linux_br.remove_interface( - bridge_name, interface) + bridge_name, interface) self.delete_device(interface) self.delete_device(device_name) self.delete_bridge(bridge_name) @@ -159,34 +159,35 @@ class LinuxBridgeAgentTest(unittest.TestCase): LOG.debug("test_remove_interface -END") def test_ensure_vlan_bridge( - self, tenant_id="test_tenant", network_name="test_network", - interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'): + self, tenant_id="test_tenant", + network_name="test_network", + interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'): LOG.debug("test_ensure_vlan_bridge - START") - new_network =\ - self._linuxbridge_plugin.create_network(tenant_id, network_name) + new_network = ( + self._linuxbridge_plugin.create_network(tenant_id, network_name)) new_port = self._linuxbridge_plugin.create_port( - tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) + tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) self._linuxbridge_plugin.plug_interface( - tenant_id, new_network[lconst.NET_ID], - new_port[lconst.PORT_ID], interface_id) + tenant_id, new_network[lconst.NET_ID], + new_port[lconst.PORT_ID], interface_id) bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11] vlan_bind = cdb.get_vlan_binding(new_network[lconst.NET_ID]) vlan_id = vlan_bind[lconst.VLANID] vlan_subinterface = self.physical_interface + '.' + str(vlan_id) self._linuxbridge_quantum_agent.linux_br.ensure_vlan_bridge( - new_network[lconst.NET_ID], str(vlan_id)) - list_quantum_bridges = self._linuxbridge_quantum_agent.linux_br.\ - get_all_quantum_bridges() + new_network[lconst.NET_ID], str(vlan_id)) + list_quantum_bridges = (self._linuxbridge_quantum_agent.linux_br. + get_all_quantum_bridges()) self.assertTrue(bridge_name in list_quantum_bridges) - list_interface = self._linuxbridge_quantum_agent.linux_br.\ - get_interfaces_on_bridge(bridge_name) + list_interface = (self._linuxbridge_quantum_agent.linux_br. + get_interfaces_on_bridge(bridge_name)) self.assertTrue(vlan_subinterface in list_interface) for interface in list_interface: self._linuxbridge_quantum_agent.linux_br.remove_interface( - bridge_name, interface) + bridge_name, interface) self.delete_device(interface) self.delete_bridge(bridge_name) self.tearDownUnplugInterface(tenant_id, new_network[lconst.NET_ID], @@ -195,26 +196,26 @@ class LinuxBridgeAgentTest(unittest.TestCase): LOG.debug("test_ensure_vlan_bridge -END") def test_delete_vlan_bridge( - self, tenant_id="test_tenant", network_name="test_network", - interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'): + self, tenant_id="test_tenant", network_name="test_network", + interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'): LOG.debug("test_delete_vlan_bridge - START") - new_network =\ - self._linuxbridge_plugin.create_network(tenant_id, network_name) + new_network = ( + self._linuxbridge_plugin.create_network(tenant_id, network_name)) new_port = self._linuxbridge_plugin.create_port( - tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) + tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) self._linuxbridge_plugin.plug_interface( - tenant_id, new_network[lconst.NET_ID], - new_port[lconst.PORT_ID], interface_id) + tenant_id, new_network[lconst.NET_ID], + new_port[lconst.PORT_ID], interface_id) bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11] vlan_bind = cdb.get_vlan_binding(new_network[lconst.NET_ID]) vlan_id = vlan_bind[lconst.VLANID] vlan_subinterface = self.physical_interface + '.' + str(vlan_id) self._linuxbridge_quantum_agent.linux_br.ensure_vlan_bridge( - new_network[lconst.NET_ID], str(vlan_id)) + new_network[lconst.NET_ID], str(vlan_id)) self._linuxbridge_quantum_agent.linux_br.delete_vlan_bridge( - bridge_name) + bridge_name) self.assertEquals(self.device_exists(vlan_subinterface), False) self.assertEquals(self.device_exists(bridge_name), False) @@ -224,26 +225,26 @@ class LinuxBridgeAgentTest(unittest.TestCase): LOG.debug("test_delete_vlan_bridge - END") def test_process_deleted_networks( - self, tenant_id="test_tenant", network_name="test_network", - interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'): + self, tenant_id="test_tenant", network_name="test_network", + interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc'): LOG.debug("test_delete_vlan_bridge - START") - new_network =\ - self._linuxbridge_plugin.create_network(tenant_id, network_name) + new_network = ( + self._linuxbridge_plugin.create_network(tenant_id, network_name)) new_port = self._linuxbridge_plugin.create_port( - tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) + tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) self._linuxbridge_plugin.plug_interface( - tenant_id, new_network[lconst.NET_ID], - new_port[lconst.PORT_ID], interface_id) + tenant_id, new_network[lconst.NET_ID], + new_port[lconst.PORT_ID], interface_id) bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11] vlan_bindings = {} - vlan_bindings[new_network[lconst.NET_ID]] =\ - cdb.get_vlan_binding(new_network[lconst.NET_ID]) + vlan_bindings[new_network[lconst.NET_ID]] = ( + cdb.get_vlan_binding(new_network[lconst.NET_ID])) vlan_id = vlan_bindings[new_network[lconst.NET_ID]][lconst.VLANID] vlan_subinterface = self.physical_interface + '.' + str(vlan_id) self._linuxbridge_quantum_agent.linux_br.ensure_vlan_bridge( - new_network[lconst.NET_ID], str(vlan_id)) + new_network[lconst.NET_ID], str(vlan_id)) self.tearDownUnplugInterface(tenant_id, new_network[lconst.NET_ID], new_port[lconst.PORT_ID]) vlan_bindings = {} @@ -254,18 +255,18 @@ class LinuxBridgeAgentTest(unittest.TestCase): LOG.debug("test_delete_vlan_bridge - END") def test_process_unplugged_tap_interface( - self, tenant_id="test_tenant", network_name="test_network", - interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc', - mac_address='fe:16:3e:51:60:dd'): + self, tenant_id="test_tenant", network_name="test_network", + interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc', + mac_address='fe:16:3e:51:60:dd'): LOG.debug("test_process_unplugged_tap_interface - START") - new_network =\ - self._linuxbridge_plugin.create_network(tenant_id, network_name) + new_network = ( + self._linuxbridge_plugin.create_network(tenant_id, network_name)) new_port = self._linuxbridge_plugin.create_port( - tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) + tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) self._linuxbridge_plugin.plug_interface( - tenant_id, new_network[lconst.NET_ID], - new_port[lconst.PORT_ID], interface_id) + tenant_id, new_network[lconst.NET_ID], + new_port[lconst.PORT_ID], interface_id) bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11] self.create_bridge(bridge_name) device_name = self.tap_name_prefix + interface_id[0:11] @@ -275,43 +276,43 @@ class LinuxBridgeAgentTest(unittest.TestCase): vlan_id = vlan_bind[lconst.VLANID] self._linuxbridge_quantum_agent.process_port_binding( - new_port[lconst.PORT_ID], new_network[lconst.NET_ID], - interface_id, str(vlan_id)) + new_port[lconst.PORT_ID], new_network[lconst.NET_ID], + interface_id, str(vlan_id)) list_interface = self._linuxbridge_quantum_agent.linux_br.\ - get_interfaces_on_bridge(bridge_name) + get_interfaces_on_bridge(bridge_name) self._linuxbridge_plugin.unplug_interface(tenant_id, new_network[lconst.NET_ID], new_port[lconst.PORT_ID]) plugged_interface = [] self._linuxbridge_quantum_agent.process_unplugged_interfaces( - plugged_interface) - list_interface = self._linuxbridge_quantum_agent.linux_br.\ - get_interfaces_on_bridge(bridge_name) + plugged_interface) + list_interface = (self._linuxbridge_quantum_agent.linux_br. + get_interfaces_on_bridge(bridge_name)) self.assertFalse(device_name in list_interface) for interface in list_interface: self._linuxbridge_quantum_agent.linux_br.remove_interface( - bridge_name, interface) + bridge_name, interface) self.delete_device(interface) self.delete_device(device_name) self.delete_bridge(bridge_name) self.tearDownNetworkPort(tenant_id, new_network[lconst.NET_ID], - new_port[lconst.PORT_ID]) + new_port[lconst.PORT_ID]) LOG.debug("test_test_process_unplugged_tap_interface -END") def test_process_unplugged_gw_interface( - self, tenant_id="test_tenant", network_name="test_network", - interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc', - mac_address='fe:16:3e:51:60:dd'): + self, tenant_id="test_tenant", network_name="test_network", + interface_id='fe701ddf-26a2-42ea-b9e6-7313d1c522cc', + mac_address='fe:16:3e:51:60:dd'): LOG.debug("test_process_unplugged_gw_interface - START") - new_network =\ - self._linuxbridge_plugin.create_network(tenant_id, network_name) + new_network = ( + self._linuxbridge_plugin.create_network(tenant_id, network_name)) new_port = self._linuxbridge_plugin.create_port( - tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) + tenant_id, new_network[lconst.NET_ID], lconst.PORT_UP) self._linuxbridge_plugin.plug_interface( - tenant_id, new_network[lconst.NET_ID], - new_port[lconst.PORT_ID], interface_id) + tenant_id, new_network[lconst.NET_ID], + new_port[lconst.PORT_ID], interface_id) bridge_name = self.br_name_prefix + new_network[lconst.NET_ID][0:11] self.create_bridge(bridge_name) device_name = self.gw_name_prefix + new_network[lconst.NET_ID][0:11] @@ -321,27 +322,27 @@ class LinuxBridgeAgentTest(unittest.TestCase): vlan_id = vlan_bind[lconst.VLANID] self._linuxbridge_quantum_agent.process_port_binding( - new_port[lconst.PORT_ID], new_network[lconst.NET_ID], - interface_id, str(vlan_id)) - list_interface = self._linuxbridge_quantum_agent.linux_br.\ - get_interfaces_on_bridge(bridge_name) + new_port[lconst.PORT_ID], new_network[lconst.NET_ID], + interface_id, str(vlan_id)) + list_interface = (self._linuxbridge_quantum_agent.linux_br. + get_interfaces_on_bridge(bridge_name)) self._linuxbridge_plugin.unplug_interface(tenant_id, new_network[lconst.NET_ID], new_port[lconst.PORT_ID]) plugged_interface = [] self._linuxbridge_quantum_agent.process_unplugged_interfaces( - plugged_interface) - list_interface = self._linuxbridge_quantum_agent.linux_br.\ - get_interfaces_on_bridge(bridge_name) + plugged_interface) + list_interface = (self._linuxbridge_quantum_agent.linux_br. + get_interfaces_on_bridge(bridge_name)) self.assertFalse(device_name in list_interface) for interface in list_interface: self._linuxbridge_quantum_agent.linux_br.remove_interface( - bridge_name, interface) + bridge_name, interface) self.delete_device(interface) self.delete_device(device_name) self.delete_bridge(bridge_name) self.tearDownNetworkPort(tenant_id, new_network[lconst.NET_ID], - new_port[lconst.PORT_ID]) + new_port[lconst.PORT_ID]) LOG.debug("test_test_process_unplugged_gw_interface -END") @@ -402,15 +403,15 @@ class LinuxBridgeAgentTest(unittest.TestCase): self.physical_interface, self.root_helper) self._linuxbridge_quantum_agent = linux_agent.LinuxBridgeQuantumAgent( - self.br_name_prefix, - self.physical_interface, - self.polling_interval, - self.root_helper) + self.br_name_prefix, + self.physical_interface, + self.polling_interval, + self.root_helper) def run_cmd(self, args): cmd = shlex.split(self.root_helper) + args LOG.debug("Running command: " + " ".join(cmd)) - p = Popen(cmd, stdout=PIPE) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) retval = p.communicate()[0] if p.returncode == -(signal.SIGALRM): LOG.debug("Timeout running command: " + " ".join(args)) diff --git a/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py b/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py index 9774c2e854..a01289d731 100755 --- a/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py +++ b/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py @@ -20,16 +20,18 @@ # @author: Dave Lapsley, Nicira Networks, Inc. import ConfigParser -import logging as LOG +import logging +from optparse import OptionParser import shlex +import signal +import subprocess import sys import time -import signal -from optparse import OptionParser from sqlalchemy.ext.sqlsoup import SqlSoup -from subprocess import * +logging.basicConfig() +LOG = logging.getLogger(__name__) # Global constants. OP_STATUS_UP = "UP" @@ -38,7 +40,9 @@ OP_STATUS_DOWN = "DOWN" # A placeholder for dead vlans. DEAD_VLAN_TAG = "4095" -REFRESH_INTERVAL = 2 +# Default interval values +DEFAULT_POLLING_INTERVAL = 2 +DEFAULT_RECONNECT_INTERVAL = 2 # A class to represent a VIF (i.e., a port that has 'iface-id' and 'vif-mac' @@ -52,9 +56,10 @@ class VifPort: self.switch = switch def __str__(self): - return "iface-id=" + self.vif_id + ", vif_mac=" + \ - self.vif_mac + ", port_name=" + self.port_name + \ - ", ofport=" + self.ofport + ", bridge name = " + self.switch.br_name + return ("iface-id=" + self.vif_id + ", vif_mac=" + + self.vif_mac + ", port_name=" + self.port_name + + ", ofport=" + self.ofport + ", bridge name = " + + self.switch.br_name) class OVSBridge: @@ -65,7 +70,7 @@ class OVSBridge: def run_cmd(self, args): cmd = shlex.split(self.root_helper) + args LOG.debug("## running command: " + " ".join(cmd)) - p = Popen(cmd, stdout=PIPE) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) retval = p.communicate()[0] if p.returncode == -(signal.SIGALRM): LOG.debug("## timeout running command: " + " ".join(cmd)) @@ -127,17 +132,17 @@ class OVSBridge: def add_tunnel_port(self, port_name, remote_ip): self.run_vsctl(["add-port", self.br_name, port_name]) self.set_db_attribute("Interface", port_name, "type", "gre") - self.set_db_attribute("Interface", port_name, "options", "remote_ip=" + - remote_ip) - self.set_db_attribute("Interface", port_name, "options", "in_key=flow") - self.set_db_attribute("Interface", port_name, "options", - "out_key=flow") + self.set_db_attribute("Interface", port_name, "options:remote_ip", + remote_ip) + self.set_db_attribute("Interface", port_name, "options:in_key", "flow") + self.set_db_attribute("Interface", port_name, "options:out_key", + "flow") return self.get_port_ofport(port_name) def add_patch_port(self, local_name, remote_name): self.run_vsctl(["add-port", self.br_name, local_name]) self.set_db_attribute("Interface", local_name, "type", "patch") - self.set_db_attribute("Interface", local_name, "options", "peer=" + + self.set_db_attribute("Interface", local_name, "options:peer", remote_name) return self.get_port_ofport(local_name) @@ -166,12 +171,13 @@ class OVSBridge: return self.db_get_map("Interface", port_name, "statistics") def get_xapi_iface_id(self, xs_vif_uuid): - return self.run_cmd( - ["xe", - "vif-param-get", - "param-name=other-config", - "param-key=nicira-iface-id", - "uuid=%s" % xs_vif_uuid]).strip() + return self.run_cmd([ + "xe", + "vif-param-get", + "param-name=other-config", + "param-key=nicira-iface-id", + "uuid=%s" % xs_vif_uuid, + ]).strip() # returns a VIF object for each VIF port def get_vif_ports(self): @@ -184,8 +190,8 @@ class OVSBridge: p = VifPort(name, ofport, external_ids["iface-id"], external_ids["attached-mac"], self) edge_ports.append(p) - elif "xs-vif-uuid" in external_ids and \ - "attached-mac" in external_ids: + elif ("xs-vif-uuid" in external_ids and + "attached-mac" in external_ids): # if this is a xenserver and iface-id is not automatically # synced to OVS from XAPI, we grab it from XAPI directly iface_id = self.get_xapi_iface_id(external_ids["xs-vif-uuid"]) @@ -210,13 +216,16 @@ class LocalVLANMapping: class OVSQuantumAgent(object): - def __init__(self, integ_br, root_helper): + def __init__(self, integ_br, root_helper, + polling_interval, reconnect_interval): self.root_helper = root_helper self.setup_integration_br(integ_br) + self.polling_interval = polling_interval + self.reconnect_interval = reconnect_interval def port_bound(self, port, vlan_id): - self.int_br.set_db_attribute("Port", port.port_name, "tag", - str(vlan_id)) + self.int_br.set_db_attribute("Port", port.port_name, + "tag", str(vlan_id)) self.int_br.delete_flows(match="in_port=%s" % port.ofport) def port_unbound(self, port, still_exists): @@ -229,26 +238,39 @@ class OVSQuantumAgent(object): # switch all traffic using L2 learning self.int_br.add_flow(priority=1, actions="normal") - def daemon_loop(self, db): + def daemon_loop(self, db_connection_url): self.local_vlan_map = {} old_local_bindings = {} old_vif_ports = {} + db_connected = False while True: + if not db_connected: + time.sleep(self.reconnect_interval) + db = SqlSoup(db_connection_url) + db_connected = True + LOG.info("Connecting to database \"%s\" on %s" % + (db.engine.url.database, db.engine.url.host)) all_bindings = {} try: ports = db.ports.all() - except: - ports = [] + except Exception as e: + LOG.info("Unable to get port bindings! Exception: %s" % e) + db_connected = False + continue + for port in ports: all_bindings[port.interface_id] = port vlan_bindings = {} try: vlan_binds = db.vlan_bindings.all() - except: - vlan_binds = [] + except Exception as e: + LOG.info("Unable to get vlan bindings! Exception: %s" % e) + db_connected = False + continue + for bind in vlan_binds: vlan_bindings[bind.network_id] = bind.vlan_id @@ -265,7 +287,8 @@ class OVSQuantumAgent(object): self.int_br.set_db_attribute("Port", p.port_name, "tag", DEAD_VLAN_TAG) self.int_br.add_flow(priority=2, - match="in_port=%s" % p.ofport, actions="drop") + match="in_port=%s" % p.ofport, + actions="drop") old_b = old_local_bindings.get(p.vif_id, None) new_b = new_local_bindings.get(p.vif_id, None) @@ -285,8 +308,9 @@ class OVSQuantumAgent(object): self.port_bound(p, vlan_id) if p.vif_id in all_bindings: all_bindings[p.vif_id].op_status = OP_STATUS_UP - LOG.info("Adding binding to net-id = %s " \ - "for %s on vlan %s" % (new_b, str(p), vlan_id)) + LOG.info(("Adding binding to net-id = %s " + "for %s on vlan %s") % + (new_b, str(p), vlan_id)) for vif_id in old_vif_ports: if vif_id not in new_vif_ports: @@ -299,8 +323,15 @@ class OVSQuantumAgent(object): old_vif_ports = new_vif_ports old_local_bindings = new_local_bindings - db.commit() - time.sleep(REFRESH_INTERVAL) + try: + db.commit() + except Exception as e: + LOG.info("Unable to commit to database! Exception: %s" % e) + db.rollback() + old_local_bindings = {} + old_vif_ports = {} + + time.sleep(self.polling_interval) class OVSQuantumTunnelAgent(object): @@ -328,7 +359,7 @@ class OVSQuantumTunnelAgent(object): MAX_VLAN_TAG = 4094 def __init__(self, integ_br, tun_br, remote_ip_file, local_ip, - root_helper): + root_helper, polling_interval, reconnect_interval): '''Constructor. :param integ_br: name of the integration bridge. @@ -342,6 +373,9 @@ class OVSQuantumTunnelAgent(object): self.setup_integration_br(integ_br) self.local_vlan_map = {} self.setup_tunnel_br(tun_br, remote_ip_file, local_ip) + self.db_connected = False + self.polling_interval = polling_interval + self.reconnect_interval = reconnect_interval def provision_local_vlan(self, net_uuid, lsw_id): '''Provisions a local VLAN. @@ -356,13 +390,13 @@ class OVSQuantumTunnelAgent(object): # outbound self.tun_br.add_flow(priority=4, match="in_port=%s,dl_vlan=%s" % - (self.patch_int_ofport, lvid), + (self.patch_int_ofport, lvid), actions="set_tunnel:%s,normal" % (lsw_id)) # inbound self.tun_br.add_flow(priority=3, match="tun_id=%s" % lsw_id, - actions="mod_vlan_vid:%s,output:%s" % (lvid, - self.patch_int_ofport)) + actions="mod_vlan_vid:%s,output:%s" % + (lvid, self.patch_int_ofport)) def reclaim_local_vlan(self, net_uuid, lvm): '''Reclaim a local VLAN. @@ -401,8 +435,8 @@ class OVSQuantumTunnelAgent(object): :param port: a VifPort object. :param net_uuid: the net_uuid this port is associated with.''' if net_uuid not in self.local_vlan_map: - LOG.info('port_unbound() net_uuid %s not in local_vlan_map' - % net_uuid) + LOG.info('port_unbound() net_uuid %s not in local_vlan_map' % + net_uuid) return lvm = self.local_vlan_map[net_uuid] @@ -459,9 +493,9 @@ class OVSQuantumTunnelAgent(object): tunnel_ips = (x for x in clean_ips if x != local_ip and x) for i, remote_ip in enumerate(tunnel_ips): self.tun_br.add_tunnel_port("gre-" + str(i), remote_ip) - except Exception, e: - LOG.error("Error configuring tunnels: '%s' %s" - % (remote_ip_file, str(e))) + except Exception as e: + LOG.error("Error configuring tunnels: '%s' %s" % + (remote_ip_file, str(e))) raise self.tun_br.remove_all_flows() @@ -478,8 +512,10 @@ class OVSQuantumTunnelAgent(object): ports = [] try: ports = db.ports.all() - except Exception, e: - LOG.info("Exception accessing db.ports: %s" % e) + except Exceptioni as e: + LOG.info("Unable to get port bindings! Exception: %s" % e) + self.db_connected = False + return {} return dict([(port.interface_id, port) for port in ports]) @@ -493,25 +529,39 @@ class OVSQuantumTunnelAgent(object): lsw_id_binds = [] try: lsw_id_binds.extend(db.vlan_bindings.all()) - except Exception, e: - LOG.info("Exception accessing db.vlan_bindings: %s" % e) + except Exception as e: + LOG.info("Unable to get vlan bindings! Exception: %s" % e) + self.db_connected = False + return {} return dict([(bind.network_id, bind.vlan_id) for bind in lsw_id_binds]) - def daemon_loop(self, db): + def daemon_loop(self, db_connection_url): '''Main processing loop (not currently used). - :param db: reference to database layer. + :param options: database information - in the event need to reconnect ''' old_local_bindings = {} old_vif_ports = {} + self.db_connected = False while True: + if not self.db_connected: + time.sleep(self.reconnect_interval) + db = SqlSoup(db_connection_url) + self.db_connected = True + LOG.info("Connecting to database \"%s\" on %s" % + (db.engine.url.database, db.engine.url.host)) + # Get bindings from db. all_bindings = self.get_db_port_bindings(db) + if not self.db_connected: + continue all_bindings_vif_port_ids = set(all_bindings.keys()) lsw_id_bindings = self.get_db_vlan_bindings(db) + if not self.db_connected: + continue # Get bindings from OVS bridge. vif_ports = self.int_br.get_vif_ports() @@ -525,11 +575,11 @@ class OVSQuantumTunnelAgent(object): new_local_bindings_ids = all_bindings_vif_port_ids.intersection( new_vif_ports_ids) new_local_bindings = dict([(p, all_bindings.get(p)) - for p in new_vif_ports_ids]) - new_bindings = set((p, old_local_bindings.get(p), - new_local_bindings.get(p)) for p in new_vif_ports_ids) - changed_bindings = set([b for b in new_bindings - if b[2] != b[1]]) + for p in new_vif_ports_ids]) + new_bindings = set( + (p, old_local_bindings.get(p), + new_local_bindings.get(p)) for p in new_vif_ports_ids) + changed_bindings = set([b for b in new_bindings if b[2] != b[1]]) LOG.debug('all_bindings: %s' % all_bindings) LOG.debug('lsw_id_bindings: %s' % lsw_id_bindings) @@ -563,7 +613,7 @@ class OVSQuantumTunnelAgent(object): new_net_uuid = new_port.network_id if new_net_uuid not in lsw_id_bindings: LOG.warn("No ls-id binding found for net-id '%s'" % - new_net_uuid) + new_net_uuid) continue lsw_id = lsw_id_bindings[new_net_uuid] @@ -572,10 +622,10 @@ class OVSQuantumTunnelAgent(object): LOG.info("Port " + str(p) + " on net-id = " + new_net_uuid + " bound to " + str(self.local_vlan_map[new_net_uuid])) - except Exception, e: + except Exception as e: LOG.info("Unable to bind Port " + str(p) + - " on netid = " + new_net_uuid + " to " - + str(self.local_vlan_map[new_net_uuid])) + " on netid = " + new_net_uuid + " to " + + str(self.local_vlan_map[new_net_uuid])) for vif_id in disappeared_vif_ports_ids: LOG.info("Port Disappeared: " + vif_id) @@ -590,7 +640,7 @@ class OVSQuantumTunnelAgent(object): old_vif_ports = new_vif_ports old_local_bindings = new_local_bindings - time.sleep(REFRESH_INTERVAL) + time.sleep(self.polling_interval) def main(): @@ -602,9 +652,9 @@ def main(): options, args = parser.parse_args() if options.verbose: - LOG.basicConfig(level=LOG.DEBUG) + LOG.setLevel(logging.DEBUG) else: - LOG.basicConfig(level=LOG.WARN) + LOG.setLevel(logging.WARNING) if len(args) != 1: parser.print_help() @@ -614,16 +664,16 @@ def main(): config = ConfigParser.ConfigParser() try: config.read(config_file) - except Exception, e: - LOG.error("Unable to parse config file \"%s\": %s" - % (config_file, str(e))) + except Exception as e: + LOG.error("Unable to parse config file \"%s\": %s" % + (config_file, str(e))) raise e # Determine which agent type to use. enable_tunneling = False try: enable_tunneling = config.getboolean("OVS", "enable-tunneling") - except Exception, e: + except Exception as e: pass # Get common parameters. @@ -636,11 +686,21 @@ def main(): if not len(db_connection_url): raise Exception('Empty db_connection_url in configuration file.') + if config.has_option("AGENT", "polling_interval"): + polling_interval = config.getint("AGENT", "polling_interval") + else: + polling_interval = DEFAULT_POLLING_INTERVAL + LOG.info("Polling interval not defined. Using default.") + if config.has_option("AGENT", "reconnect_interval"): + reconnect_interval = config.getint("AGENT", "reconnect_interval") + else: + reconnect_interval = DEFAULT_RECONNECT_INTERVAL + LOG.info("Reconnect interval not defined. Using default.") root_helper = config.get("AGENT", "root_helper") - except Exception, e: - LOG.error("Error parsing common params in config_file: '%s': %s" - % (config_file, str(e))) + except Exception as e: + LOG.error("Error parsing common params in config_file: '%s': %s" % + (config_file, str(e))) sys.exit(1) if enable_tunneling: @@ -661,24 +721,22 @@ def main(): local_ip = config.get("OVS", "local-ip") if not len(local_ip): raise Exception('Empty local-ip in configuration file.') - except Exception, e: - LOG.error("Error parsing tunnel params in config_file: '%s': %s" - % (config_file, str(e))) + + except Exception as e: + LOG.error("Error parsing tunnel params in config_file: '%s': %s" % + (config_file, str(e))) sys.exit(1) plugin = OVSQuantumTunnelAgent(integ_br, tun_br, remote_ip_file, - local_ip, root_helper) + local_ip, root_helper, + polling_interval, reconnect_interval) else: # Get parameters for OVSQuantumAgent. - plugin = OVSQuantumAgent(integ_br, root_helper) + plugin = OVSQuantumAgent(integ_br, root_helper, + polling_interval, reconnect_interval) # Start everything. - options = {"sql_connection": db_connection_url} - db = SqlSoup(options["sql_connection"]) - LOG.info("Connecting to database \"%s\" on %s" % - (db.engine.url.database, db.engine.url.host)) - - plugin.daemon_loop(db) + plugin.daemon_loop(db_connection_url) sys.exit(0) diff --git a/quantum/plugins/openvswitch/tests/unit/test_tunnel.py b/quantum/plugins/openvswitch/tests/unit/test_tunnel.py index ee408f929b..12011787ca 100644 --- a/quantum/plugins/openvswitch/tests/unit/test_tunnel.py +++ b/quantum/plugins/openvswitch/tests/unit/test_tunnel.py @@ -89,7 +89,7 @@ class TunnelTest(unittest.TestCase): self.TUN_BRIDGE, REMOTE_IP_FILE, '10.0.0.1', - 'sudo') + 'sudo', 2, 2) self.mox.VerifyAll() def testProvisionLocalVlan(self): @@ -109,7 +109,7 @@ class TunnelTest(unittest.TestCase): self.TUN_BRIDGE, REMOTE_IP_FILE, '10.0.0.1', - 'sudo') + 'sudo', 2, 2) a.available_local_vlans = set([LV_ID]) a.provision_local_vlan(NET_UUID, LS_ID) self.mox.VerifyAll() @@ -126,7 +126,7 @@ class TunnelTest(unittest.TestCase): self.TUN_BRIDGE, REMOTE_IP_FILE, '10.0.0.1', - 'sudo') + 'sudo', 2, 2) a.available_local_vlans = set() a.local_vlan_map[NET_UUID] = LVM a.reclaim_local_vlan(NET_UUID, LVM) @@ -143,7 +143,7 @@ class TunnelTest(unittest.TestCase): self.TUN_BRIDGE, REMOTE_IP_FILE, '10.0.0.1', - 'sudo') + 'sudo', 2, 2) a.local_vlan_map[NET_UUID] = LVM a.port_bound(VIF_PORT, NET_UUID, LS_ID) self.mox.VerifyAll() @@ -154,7 +154,7 @@ class TunnelTest(unittest.TestCase): self.TUN_BRIDGE, REMOTE_IP_FILE, '10.0.0.1', - 'sudo') + 'sudo', 2, 2) a.available_local_vlans = set([LV_ID]) a.local_vlan_map[NET_UUID] = LVM a.port_unbound(VIF_PORT, NET_UUID) @@ -173,7 +173,7 @@ class TunnelTest(unittest.TestCase): self.TUN_BRIDGE, REMOTE_IP_FILE, '10.0.0.1', - 'sudo') + 'sudo', 2, 2) a.available_local_vlans = set([LV_ID]) a.local_vlan_map[NET_UUID] = LVM a.port_dead(VIF_PORT) @@ -196,7 +196,7 @@ class TunnelTest(unittest.TestCase): self.TUN_BRIDGE, REMOTE_IP_FILE, '10.0.0.1', - 'sudo') + 'sudo', 2, 2) all_bindings = a.get_db_port_bindings(db) lsw_id_bindings = a.get_db_vlan_bindings(db)