]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
plugin/ryu: make live-migration work with Ryu plugin
authorIsaku Yamahata <yamahata@valinux.co.jp>
Tue, 20 Nov 2012 05:41:04 +0000 (14:41 +0900)
committerIsaku Yamahata <yamahata@valinux.co.jp>
Mon, 3 Dec 2012 11:05:26 +0000 (20:05 +0900)
Fixes bug 1085861

Live-migration with Ryu plugin doesn't work because the unique constraint of
PortBinding table is violated as follows.
Now Ryu can handle those informations itself, so remove the table itself and
simplify Ryu plugin.

> ERROR [quantum.api.v2.resource] update failed
> Traceback (most recent call last):
>   File "/quantum/api/v2/resource.py", line 95, in resource
>     result = method(request=request, **args)
>   File "/quantum/api/v2/base.py", line 397, in update
>     obj = obj_updater(request.context, id, **kwargs)
>   File "/quantum/plugins/ryu/ryu_quantum_plugin.py", line 226, in update_port
>     port_binding.dpid, port_binding.port_no))
> InvalidInput: Invalid input for operation: invalid (datapath_id, port_no) requested (00002eab88ec5140, 4), but (0000c2f19014c74a, 1).

Change-Id: I7d993fd01125a27f6bf8e1b3fcac79ddcb8cb361

quantum/plugins/ryu/agent/ryu_quantum_agent.py
quantum/plugins/ryu/db/api_v2.py
quantum/plugins/ryu/db/models_v2.py
quantum/plugins/ryu/ryu_quantum_plugin.py

index 344b1e10b7f7cf817bc21afcf078077feaba94aa..b19e9dbe71ac3598f62867f80824d935f4485e73 100755 (executable)
@@ -36,10 +36,13 @@ from quantum.common import config as logging_config
 from quantum.openstack.common import cfg
 from quantum.openstack.common.cfg import NoSuchGroupError
 from quantum.openstack.common.cfg import NoSuchOptError
-from quantum.openstack.common import log as LOG
+from quantum.openstack.common import log
 from quantum.plugins.ryu.common import config
 
 
+LOG = log.getLogger(__name__)
+
+
 # This is copied of nova.flags._get_my_ip()
 # Agent shouldn't depend on nova module
 def _get_my_ip():
index 79d0e5043d8ca4c2e36265955d89226420b5e3fe..18dd465559a9a41cd0380b4ba59b83ecfb9b7184 100644 (file)
@@ -187,46 +187,6 @@ class TunnelKey(object):
         return session.query(ryu_models_v2.TunnelKey).all()
 
 
-def port_binding_create(port_id, net_id, dpid, port_no):
-    session = db.get_session()
-    session.query(models_v2.Port).filter(
-        models_v2.Port.network_id == net_id).filter(
-            models_v2.Port.id == port_id).one()  # confirm port exists
-    with session.begin():
-        port_binding = ryu_models_v2.PortBinding(net_id, port_id,
-                                                 dpid, port_no)
-        session.add(port_binding)
-        session.flush()
-        return port_binding
-
-
-def port_binding_get(port_id, net_id):
-    session = db.get_session()
-    session.query(models_v2.Port).filter(
-        models_v2.Port.network_id == net_id).filter(
-            models_v2.Port.id == port_id).one()  # confirm port exists
-    return session.query(ryu_models_v2.PortBinding).filter_by(
-        network_id=net_id).filter_by(port_id=port_id).one()
-
-
-def port_binding_destroy(session, port_id, net_id):
-    try:
-        session.query(models_v2.Port).filter(
-            models_v2.Port.network_id == net_id).filter(
-                models_v2.Port.id == port_id).one()  # confirm port exists
-        port_binding = session.query(ryu_models_v2.PortBinding).filter_by(
-            network_id=net_id).filter_by(port_id=port_id).one()
-        session.delete(port_binding)
-        session.flush()
-        return port_binding
-    except orm_exc.NoResultFound:
-        raise q_exc.PortNotFound(port_id=port_id, net_id=net_id)
-
-
-def port_binding_all_list(session):
-    return session.query(ryu_models_v2.PortBinding).all()
-
-
 def set_port_status(session, port_id, status):
     try:
         port = session.query(models_v2.Port).filter_by(id=port_id).one()
index e1d25ea12d1a45a03169f01659735157c079d8e4..1f335e54549ade70a27eb6d709125e99d1f53fb8 100644 (file)
@@ -52,28 +52,3 @@ class TunnelKey(model_base.BASEV2):
 
     def __repr__(self):
         return "<TunnelKey(%s,%x)>" % (self.network_id, self.tunnel_key)
-
-
-class PortBinding(model_base.BASEV2):
-    """Represents Port binding to ovs ports."""
-    __tablename__ = 'port_binding'
-
-    id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
-    network_id = sa.Column(sa.String(255), sa.ForeignKey("networks.id"),
-                           nullable=False)
-    port_id = sa.Column(sa.String(255), sa.ForeignKey("ports.id"), unique=True,
-                        nullable=False)
-    dpid = sa.Column(sa.String(255), nullable=False)
-    port_no = sa.Column(sa.Integer, nullable=False)
-
-    def __init__(self, network_id, port_id, dpid, port_no):
-        self.network_id = network_id
-        self.port_id = port_id
-        self.dpid = dpid
-        self.port_no = port_no
-
-    def __repr__(self):
-        return "<PortBinding(%s,%s,%s,%s,%s)>" % (self.network_id,
-                                                  self.port_id,
-                                                  self.dpid,
-                                                  self.port_no)
index 90792ea1f0583ce605636f347cb351095b7464ea..820b562e6b357621a67c43567aab136570abaf96 100644 (file)
 # @author: Isaku Yamahata
 
 from ryu.app import client
-from ryu.app.client import ignore_http_not_found
 from ryu.app import rest_nw_id
-from sqlalchemy.exc import IntegrityError
-from sqlalchemy.orm import exc as orm_exc
 
 from quantum.common import constants as q_const
 from quantum.common import exceptions as q_exc
@@ -68,6 +65,7 @@ class RyuQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
 
         self.client = client.OFPClient(ofp_api_host)
         self.tun_client = client.TunnelClient(ofp_api_host)
+        self.iface_client = client.QuantumIfaceClient(ofp_api_host)
         for nw_id in rest_nw_id.RESERVED_NETWORK_IDS:
             if nw_id != rest_nw_id.NW_ID_UNKNOWN:
                 self.client.update_network(nw_id)
@@ -89,20 +87,8 @@ class RyuQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
         for tun in self.tunnel_key.all_list():
             self.tun_client.update_tunnel_key(tun.network_id, tun.tunnel_key)
         session = db.get_session()
-        for port_binding in db_api_v2.port_binding_all_list(session):
-            network_id = port_binding.network_id
-            dpid = port_binding.dpid
-            port_no = port_binding.port_no
-            try:
-                port = session.query(models_v2.Port).filter(
-                    models_v2.Port.id == port_binding.port_id).one()
-            except orm_exc.NoResultFound:
-                continue
-            except orm_exc.MultipleResultsFound:
-                continue
-
-            self.client.update_port(network_id, dpid, port_no)
-            self.client.update_mac(network_id, dpid, port_no, port.mac_address)
+        for port in session.query(models_v2.Port).all():
+            self.iface_client.update_network_id(port.id, port.network_id)
 
     def _client_create_network(self, net_id, tunnel_key):
         self.client.create_network(net_id)
@@ -161,21 +147,12 @@ class RyuQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
 
         return [self._fields(net, fields) for net in nets]
 
-    def delete_port(self, context, id, l3_port_check=True):
-        with context.session.begin(subtransactions=True):
-            port = self._get_port(context, id)
-            net_id = port.network_id
-            try:
-                port_binding = db_api_v2.port_binding_destroy(context.session,
-                                                              port.id, net_id)
-                datapath_id = port_binding.dpid
-                port_no = port_binding.port_no
-                ignore_http_not_found(
-                    lambda: self.client.delete_port(net_id, datapath_id,
-                                                    port_no))
-            except q_exc.PortNotFound:
-                pass
+    def create_port(self, context, port):
+        port = super(RyuQuantumPluginV2, self).create_port(context, port)
+        self.iface_client.create_network_id(port['id'], port['network_id'])
+        return port
 
+    def delete_port(self, context, id, l3_port_check=True):
         # if needed, check to see if this is a port owned by
         # and l3-router. If so, we should prevent deletion.
         if l3_port_check:
@@ -184,52 +161,9 @@ class RyuQuantumPluginV2(db_base_plugin_v2.QuantumDbPluginV2,
         return super(RyuQuantumPluginV2, self).delete_port(context, id)
 
     def update_port(self, context, id, port):
-        p = super(RyuQuantumPluginV2, self).update_port(context, id, port)
-        net_id = p['network_id']
-        mac_address = p['mac_address']
-
         deleted = port['port'].get('deleted', False)
+        port = super(RyuQuantumPluginV2, self).update_port(context, id, port)
         if deleted:
             session = context.session
-            try:
-                db_api_v2.port_binding_destroy(session, id, net_id)
-            except q_exc.PortNotFound:
-                pass
             db_api_v2.set_port_status(session, id, q_const.PORT_STATUS_DOWN)
-            return p
-
-        datapath_id = port['port'].get('datapath_id', None)
-        port_no = port['port'].get('port_no', None)
-        if datapath_id is None or port_no is None:
-            LOG.debug('p %s', p)
-            return p
-
-        try:
-            port_binding = db_api_v2.port_binding_get(id, net_id)
-        except orm_exc.NoResultFound:
-            try:
-                db_api_v2.port_binding_create(id, net_id, datapath_id, port_no)
-            except IntegrityError:
-                # TODO:XXX should do transaction?
-                return p
-            else:
-                self.client.create_port(net_id, datapath_id, port_no)
-                self.client.create_mac(net_id, datapath_id, port_no,
-                                       mac_address)
-        else:
-            if (port_binding.dpid != datapath_id or
-                    port_binding.port_no != port_no):
-                variables = {'datapath_id': datapath_id,
-                             'port_no': port_no,
-                             'port_binding_dpid': port_binding.dpid,
-                             'port_binding_port_no': port_binding.port_no}
-                raise q_exc.InvalidInput(
-                    error_message=_('invalid (datapath_id, port_no) '
-                                    'is requested'
-                                    '(%(datapath_id)s, %(port_no)s), acutal'
-                                    '(%(port_binding_dpid)s, '
-                                    '%(port_binding_port_no)s)') % variables)
-            self.client.update_network(net_id)
-            self.client.update_port(net_id, datapath_id, port_no)
-            self.client.update_mac(net_id, datapath_id, port_no, mac_address)
-        return p
+        return port