]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Port location tracking for BigSwitch Plugin
authorKevin Benton <kevin.benton@bigswitch.com>
Mon, 24 Jun 2013 21:44:10 +0000 (14:44 -0700)
committerKevin Benton <kevin.benton@bigswitch.com>
Tue, 25 Jun 2013 23:47:53 +0000 (16:47 -0700)
Adds a new table to the Big Switch plugin to keep track of
the nova compute node host IDs that ports reside on.
This table is then used to allow users to override
the VIF type for a compute node based on the host ID.
This allows quantum to control an environment with multiple
VIF types.

Change-Id: I63eb66d970650237aed2d5dc6676a6d097988f8d
Implements: blueprint hostid-vif-override

etc/quantum/plugins/bigswitch/restproxy.ini
quantum/db/migration/alembic_migrations/versions/3cabb850f4a5_table_to_track_port_.py [new file with mode: 0644]
quantum/extensions/portbindings.py
quantum/plugins/bigswitch/db/__init__.py [new file with mode: 0644]
quantum/plugins/bigswitch/db/porttracker_db.py [new file with mode: 0644]
quantum/plugins/bigswitch/plugin.py
quantum/tests/unit/bigswitch/etc/restproxy.ini.test
quantum/tests/unit/bigswitch/test_restproxy_plugin.py

index e69d5bb753c0e0d3c28c79a803d3905c25c1c369..bfc5719b0462cc880814d55ce89216809c136004 100644 (file)
@@ -51,6 +51,14 @@ servers=localhost:8080
 #    default: ovs
 # vif_type = ovs
 
+# Overrides for vif types based on nova compute node host IDs
+# Comma separated list of host IDs to fix to a specific VIF type
+# The VIF type is taken from the end of the configuration item
+# node_override_vif_<vif_type>
+# For example, the following would set the VIF type to IVS for
+# host-id1 and host-id2
+# node_overrride_vif_ivs=host-id1,host-id2
+
 [router]
 # Specify the default router rules installed in newly created tenant routers
 # Specify multiple times for multiple rules
diff --git a/quantum/db/migration/alembic_migrations/versions/3cabb850f4a5_table_to_track_port_.py b/quantum/db/migration/alembic_migrations/versions/3cabb850f4a5_table_to_track_port_.py
new file mode 100644 (file)
index 0000000..744761d
--- /dev/null
@@ -0,0 +1,63 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013 OpenStack Foundation
+#
+#    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.
+#
+
+"""Table to track port to host associations
+
+Revision ID: 3cabb850f4a5
+Revises: 5918cbddab04
+Create Date: 2013-06-24 14:30:33.533562
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '3cabb850f4a5'
+down_revision = '5918cbddab04'
+
+# Change to ['*'] if this migration applies to all plugins
+
+migration_for_plugins = [
+    'quantum.plugins.bigswitch.plugin.QuantumRestProxyV2'
+]
+
+from alembic import op
+import sqlalchemy as sa
+
+
+from quantum.db import migration
+
+
+def upgrade(active_plugin=None, options=None):
+    if not migration.should_run(active_plugin, migration_for_plugins):
+        return
+
+    ### commands auto generated by Alembic - please adjust! ###
+    op.create_table('portlocations',
+                    sa.Column('port_id', sa.String(length=255),
+                              primary_key=True, nullable=False),
+                    sa.Column('host_id',
+                              sa.String(length=255), nullable=False)
+                    )
+    ### end Alembic commands ###
+
+
+def downgrade(active_plugin=None, options=None):
+    if not migration.should_run(active_plugin, migration_for_plugins):
+        return
+
+    ### commands auto generated by Alembic - please adjust! ###
+    op.drop_table('portlocations')
+    ### end Alembic commands ###
index f99c29dfe5b27ba3b0acd38351f0b9f8f1e4447b..087dea866d87778d1668ba029351cc5d614b12e7 100644 (file)
@@ -44,6 +44,10 @@ VIF_TYPE_802_QBG = '802.1qbg'
 VIF_TYPE_802_QBH = '802.1qbh'
 VIF_TYPE_HYPERV = 'hyperv'
 VIF_TYPE_OTHER = 'other'
+VIF_TYPES = [VIF_TYPE_UNBOUND, VIF_TYPE_BINDING_FAILED, VIF_TYPE_OVS,
+             VIF_TYPE_IVS, VIF_TYPE_BRIDGE, VIF_TYPE_802_QBG,
+             VIF_TYPE_802_QBH, VIF_TYPE_HYPERV, VIF_TYPE_OTHER]
+
 
 EXTENDED_ATTRIBUTES_2_0 = {
     'ports': {
diff --git a/quantum/plugins/bigswitch/db/__init__.py b/quantum/plugins/bigswitch/db/__init__.py
new file mode 100644 (file)
index 0000000..c05daec
--- /dev/null
@@ -0,0 +1,18 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Big Switch Networks, Inc.
+# 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.
+#
+# @author: Kevin Benton, Big Switch Networks, Inc.
diff --git a/quantum/plugins/bigswitch/db/porttracker_db.py b/quantum/plugins/bigswitch/db/porttracker_db.py
new file mode 100644 (file)
index 0000000..c286d63
--- /dev/null
@@ -0,0 +1,46 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013, Big Switch Networks
+# 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 sqlalchemy as sa
+
+from quantum.db import model_base
+from quantum.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
+
+class PortLocation(model_base.BASEV2):
+    port_id = sa.Column(sa.String(255), primary_key=True)
+    host_id = sa.Column(sa.String(255), nullable=False)
+
+
+def get_port_hostid(context, port_id):
+    with context.session.begin(subtransactions=True):
+        query = context.session.query(PortLocation)
+        res = query.filter_by(port_id=port_id).first()
+    if not res:
+        return False
+    return res.host_id
+
+
+def put_port_hostid(context, port_id, host_id):
+    if port_id == '':
+        LOG.warning(_("Received an empty port ID for host '%s'"), host_id)
+        return
+    with context.session.begin(subtransactions=True):
+        location = PortLocation(port_id=port_id, host_id=host_id)
+        context.session.add(location)
index a795ddb2f521bcf4bf0d4539c7722aa827b14561..e2e9f83d9e103513e85e8e4d8e90cb76e9c569de 100644 (file)
@@ -68,6 +68,7 @@ from quantum.extensions import l3
 from quantum.extensions import portbindings
 from quantum.openstack.common import log as logging
 from quantum.openstack.common import rpc
+from quantum.plugins.bigswitch.db import porttracker_db
 from quantum.plugins.bigswitch import routerrule_db
 from quantum.plugins.bigswitch.version import version_string_with_vcs
 
@@ -126,6 +127,15 @@ nova_opts = [
                       "Nova compute nodes")),
 ]
 
+# Each VIF Type can have a list of nova host IDs that are fixed to that type
+for i in portbindings.VIF_TYPES:
+    opt = cfg.ListOpt('node_override_vif_' + i, default=[],
+                      help=_("Nova compute nodes to manually set VIF "
+                             "type to %s") % i)
+    nova_opts.append(opt)
+
+# Add the vif types for reference later
+nova_opts.append(cfg.ListOpt('vif_types', default=portbindings.VIF_TYPES))
 
 cfg.CONF.register_opts(nova_opts, "NOVA")
 
@@ -569,6 +579,10 @@ class QuantumRestProxyV2(db_base_plugin_v2.QuantumDbPluginV2,
 
         # Update DB
         port["port"]["admin_state_up"] = False
+        if (portbindings.HOST_ID in port['port']
+            and 'device_id' in port['port']):
+            porttracker_db.put_port_hostid(context, port['port']['device_id'],
+                                           port['port'][portbindings.HOST_ID])
         new_port = super(QuantumRestProxyV2, self).create_port(context, port)
         net = super(QuantumRestProxyV2,
                     self).get_network(context, new_port["network_id"])
@@ -661,7 +675,10 @@ class QuantumRestProxyV2(db_base_plugin_v2.QuantumDbPluginV2,
         # Update DB
         new_port = super(QuantumRestProxyV2, self).update_port(context,
                                                                port_id, port)
-
+        if (portbindings.HOST_ID in port['port']
+            and 'device_id' in port['port']):
+            porttracker_db.put_port_hostid(context, port['port']['device_id'],
+                                           port['port'][portbindings.HOST_ID])
         # update on networl ctrl
         try:
             resource = PORTS_PATH % (orig_port["tenant_id"],
@@ -1335,10 +1352,21 @@ class QuantumRestProxyV2(db_base_plugin_v2.QuantumDbPluginV2,
                           "[%s]. Defaulting to ovs. "),
                         cfg_vif_type)
             cfg_vif_type = portbindings.VIF_TYPE_OVS
-
+        hostid = porttracker_db.get_port_hostid(context,
+                                                port.get("device_id"))
+        if hostid:
+            override = self._check_hostvif_override(hostid)
+            if override:
+                cfg_vif_type = override
         port[portbindings.VIF_TYPE] = cfg_vif_type
 
         port[portbindings.CAPABILITIES] = {
             portbindings.CAP_PORT_FILTER:
             'security-group' in self.supported_extension_aliases}
         return port
+
+    def _check_hostvif_override(self, hostid):
+        for v in cfg.CONF.NOVA.vif_types:
+            if hostid in getattr(cfg.CONF.NOVA, "node_override_vif_" + v, []):
+                return v
+        return False
index a54a7b60d4259a2211f537c1b8f76b0cc0741315..0a2eedb7a183fb2c186b162e3ddc769408c2892d 100644 (file)
@@ -30,6 +30,9 @@ serverssl=False
 #   options: ivs or ovs
 #   default: ovs
 vif_type = ovs
+# Overrides for vif types based on nova compute node host IDs
+# Comma separated list of host IDs to fix to a specific VIF type
+node_override_vif_ivs = ivshost
 
 [router]
 # Specify the default router rules installed in newly created tenant routers
index b6174fb8c606c886884f179422545075236ebbee..edbb2d5adfd35ce7bcc241e6136e7352c4d11f98 100644 (file)
@@ -19,6 +19,7 @@ import os
 
 from mock import patch
 from oslo.config import cfg
+import webob.exc
 
 import quantum.common.test_lib as test_lib
 from quantum.extensions import portbindings
@@ -106,6 +107,38 @@ class TestBigSwitchProxyPortsV2IVS(test_plugin.TestPortsV2,
         cfg.CONF.set_override('vif_type', 'ivs', 'NOVA')
 
 
+class TestBigSwitchVIFOverride(test_plugin.TestPortsV2,
+                               BigSwitchProxyPluginV2TestCase,
+                               test_bindings.PortBindingsTestCase):
+    VIF_TYPE = portbindings.VIF_TYPE_OVS
+    HAS_PORT_FILTER = False
+
+    def setUp(self):
+        super(TestBigSwitchVIFOverride,
+              self).setUp()
+        cfg.CONF.set_override('vif_type', 'ovs', 'NOVA')
+
+    def test_port_vif_details(self):
+        kwargs = {'name': 'name', 'binding:host_id': 'ivshost',
+                  'device_id': 'override_dev'}
+        with self.port(**kwargs) as port:
+            self.assertEqual(port['port']['binding:vif_type'],
+                             portbindings.VIF_TYPE_IVS)
+        kwargs = {'name': 'name2', 'binding:host_id': 'someotherhost',
+                  'device_id': 'other_dev'}
+        with self.port(**kwargs) as port:
+            self.assertEqual(port['port']['binding:vif_type'], self.VIF_TYPE)
+
+    def _make_port(self, fmt, net_id, expected_res_status=None, **kwargs):
+        res = self._create_port(fmt, net_id, expected_res_status,
+                                ('binding:host_id', ), **kwargs)
+        # Things can go wrong - raise HTTP exc with res code only
+        # so it can be caught by unit tests
+        if res.status_int >= 400:
+            raise webob.exc.HTTPClientError(code=res.status_int)
+        return self.deserialize(fmt, res)
+
+
 class TestBigSwitchProxyNetworksV2(test_plugin.TestNetworksV2,
                                    BigSwitchProxyPluginV2TestCase):