Port location tracking for BigSwitch Plugin

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
This commit is contained in:
Kevin Benton 2013-06-24 14:44:10 -07:00
parent 23284e7c57
commit d3dd33bc30
8 changed files with 205 additions and 2 deletions

View 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

View File

@ -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 ###

View 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': {

View File

@ -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.

View File

@ -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)

View 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

View 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

View 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):