From: Gary Kotton Date: Thu, 28 Jun 2012 10:26:10 +0000 (-0400) Subject: v2 support for the linux bridge plugin X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=b0f43d77b8348dce84b5b578d7efeec84ba3a51d;p=openstack-build%2Fneutron-build.git v2 support for the linux bridge plugin blueprint lb-api-v2-support Plugin support for the linuxbridge using the v2 API 1. The core_plugin in quantum.conf must be set to: quantum.plugins.linuxbridge.LinuxBridgePluginV2.LinuxBridgePluginV2 2. By default the agent is v2. A configuration file entry 'target_v2_api' in the section 'AGENT' can be set as False to support v1. Change-Id: I2e196859c13b28e535c6ec394ec3f5bc907bf019 --- diff --git a/quantum/plugins/linuxbridge/LinuxBridgePluginV2.py b/quantum/plugins/linuxbridge/LinuxBridgePluginV2.py new file mode 100644 index 000000000..492081227 --- /dev/null +++ b/quantum/plugins/linuxbridge/LinuxBridgePluginV2.py @@ -0,0 +1,54 @@ +# Copyright (c) 2012 OpenStack, LLC. +# +# 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 logging + +from quantum.db import db_base_plugin_v2 +from quantum.db import models_v2 +from quantum.plugins.linuxbridge.db import l2network_db as cdb + +LOG = logging.getLogger(__name__) + + +class LinuxBridgePluginV2(db_base_plugin_v2.QuantumDbPluginV2): + """ + LinuxBridgePlugin provides support for Quantum abstractions + using LinuxBridge. A new VLAN is created for each network. + It relies on an agent to perform the actual bridge configuration + on each host. + """ + + def __init__(self): + cdb.initialize(base=models_v2.model_base.BASEV2) + LOG.debug("Linux Bridge Plugin initialization complete") + + def create_network(self, context, network): + new_network = super(LinuxBridgePluginV2, self).create_network(context, + network) + try: + vlan_id = cdb.reserve_vlanid() + cdb.add_vlan_binding(vlan_id, new_network['id']) + except: + super(LinuxBridgePluginV2, self).delete_network(context, + new_network['id']) + raise + + return new_network + + def delete_network(self, context, id): + vlan_binding = cdb.get_vlan_binding(id) + cdb.release_vlanid(vlan_binding[const.VLANID]) + cdb.remove_vlan_binding(id) + return super(LinuxBridgePluginV2, self).delete_network(context, id) diff --git a/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py b/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py index 91a1e3218..4168d784a 100755 --- a/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py +++ b/quantum/plugins/linuxbridge/agent/linuxbridge_quantum_agent.py @@ -314,12 +314,13 @@ class LinuxBridge: class LinuxBridgeQuantumAgent: def __init__(self, br_name_prefix, physical_interface, polling_interval, - reconnect_interval, root_helper): + reconnect_interval, root_helper, target_v2_api): 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 + self.target_v2_api = target_v2_api def setup_linux_bridge(self, br_name_prefix, physical_interface): self.linux_br = LinuxBridge(br_name_prefix, physical_interface, @@ -407,25 +408,41 @@ class LinuxBridgeQuantumAgent: 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': + append_entry = False + if self.target_v2_api: + all_bindings[bind.id] = bind + entry = {'network_id': bind.network_id, + 'uuid': bind.id, + 'status': bind.status, + 'interface_id': bind.id} + append_entry = bind.admin_state_up + else: + 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} + append_entry = bind.state == 'ACTIVE' + if append_entry: port_bindings.append(entry) plugged_interfaces = [] 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']) - if self.process_port_binding(pb['uuid'], - pb['network_id'], - pb['interface_id'], - vlan_id): - all_bindings[pb['uuid']].op_status = OP_STATUS_UP - plugged_interfaces.append(pb['interface_id']) + port_id = pb['uuid'] + interface_id = pb['interface_id'] + + vlan_id = str(vlan_bindings[pb['network_id']]['vlan_id']) + if self.process_port_binding(port_id, + pb['network_id'], + interface_id, + vlan_id): + if self.target_v2_api: + all_bindings[port_id].status = OP_STATUS_UP + else: + all_bindings[port_id].op_status = OP_STATUS_UP + + plugged_interfaces.append(interface_id) if old_port_bindings != port_bindings: LOG.debug("Port-bindings: %s" % ports_string) @@ -495,11 +512,9 @@ def main(): root_helper = conf.AGENT.root_helper 'Establish database connection and load models' db_connection_url = conf.DATABASE.sql_connection - LOG.info("Connecting to %s" % (db_connection_url)) - plugin = LinuxBridgeQuantumAgent(br_name_prefix, physical_interface, polling_interval, reconnect_interval, - root_helper) + root_helper, conf.AGENT.target_v2_api) LOG.info("Agent initialized successfully, now running... ") plugin.daemon_loop(db_connection_url) diff --git a/quantum/plugins/linuxbridge/common/config.py b/quantum/plugins/linuxbridge/common/config.py index 85cc907bc..7e77147f4 100644 --- a/quantum/plugins/linuxbridge/common/config.py +++ b/quantum/plugins/linuxbridge/common/config.py @@ -37,6 +37,7 @@ bridge_opts = [ agent_opts = [ cfg.IntOpt('polling_interval', default=2), cfg.StrOpt('root_helper', default='sudo'), + cfg.BoolOpt('target_v2_api', default=False), ] diff --git a/quantum/plugins/linuxbridge/db/l2network_db.py b/quantum/plugins/linuxbridge/db/l2network_db.py index 8b32614a3..b661c700e 100644 --- a/quantum/plugins/linuxbridge/db/l2network_db.py +++ b/quantum/plugins/linuxbridge/db/l2network_db.py @@ -26,16 +26,24 @@ import quantum.db.api as db from quantum.plugins.linuxbridge.common import config from quantum.plugins.linuxbridge.common import exceptions as c_exc from quantum.plugins.linuxbridge.db import l2network_models +from quantum.plugins.linuxbridge.db import l2network_models_v2 LOG = logging.getLogger(__name__) CONF_FILE = find_config_file({'plugin': 'linuxbridge'}, "linuxbridge_conf.ini") CONF = config.parse(CONF_FILE) +# The global variable for the database version model +L2_MODEL = l2network_models -def initialize(): + +def initialize(base=None): + global L2_MODEL options = {"sql_connection": "%s" % CONF.DATABASE.sql_connection} options.update({"reconnect_interval": CONF.DATABASE.reconnect_interval}) + if base: + options.update({"base": base}) + L2_MODEL = l2network_models_v2 db.configure_db(options) create_vlanids() @@ -47,7 +55,7 @@ def create_vlanids(): start = CONF.VLANS.vlan_start end = CONF.VLANS.vlan_end try: - vlanid = session.query(l2network_models.VlanID).one() + vlanid = session.query(L2_MODEL.VlanID).one() except exc.MultipleResultsFound: """ TODO (Sumit): Salvatore rightly points out that this will not handle @@ -57,10 +65,10 @@ def create_vlanids(): Per Dan's suggestion we just throw a server exception for now. """ current_start = ( - int(session.query(func.min(l2network_models.VlanID.vlan_id)). + int(session.query(func.min(L2_MODEL.VlanID.vlan_id)). one()[0])) current_end = ( - int(session.query(func.max(l2network_models.VlanID.vlan_id)). + int(session.query(func.max(L2_MODEL.VlanID.vlan_id)). one()[0])) if current_start != start or current_end != end: LOG.debug("Old VLAN range %s-%s" % (current_start, current_end)) @@ -70,7 +78,7 @@ def create_vlanids(): except exc.NoResultFound: LOG.debug("Setting VLAN range to %s-%s" % (start, end)) while start <= end: - vlanid = l2network_models.VlanID(start) + vlanid = L2_MODEL.VlanID(start) session.add(vlanid) start += 1 session.flush() @@ -82,7 +90,7 @@ def get_all_vlanids(): LOG.debug("get_all_vlanids() called") session = db.get_session() try: - vlanids = (session.query(l2network_models.VlanID). + vlanids = (session.query(L2_MODEL.VlanID). all()) return vlanids except exc.NoResultFound: @@ -94,7 +102,7 @@ def is_vlanid_used(vlan_id): LOG.debug("is_vlanid_used() called") session = db.get_session() try: - vlanid = (session.query(l2network_models.VlanID). + vlanid = (session.query(L2_MODEL.VlanID). filter_by(vlan_id=vlan_id). one()) return vlanid["vlan_used"] @@ -107,7 +115,7 @@ def release_vlanid(vlan_id): LOG.debug("release_vlanid() called") session = db.get_session() try: - vlanid = (session.query(l2network_models.VlanID). + vlanid = (session.query(L2_MODEL.VlanID). filter_by(vlan_id=vlan_id). one()) vlanid["vlan_used"] = False @@ -124,7 +132,7 @@ def delete_vlanid(vlan_id): LOG.debug("delete_vlanid() called") session = db.get_session() try: - vlanid = (session.query(l2network_models.VlanID). + vlanid = (session.query(L2_MODEL.VlanID). filter_by(vlan_id=vlan_id). one()) session.delete(vlanid) @@ -139,18 +147,18 @@ def reserve_vlanid(): LOG.debug("reserve_vlanid() called") session = db.get_session() try: - rvlan = (session.query(l2network_models.VlanID). + rvlan = (session.query(L2_MODEL.VlanID). first()) if not rvlan: create_vlanids() - rvlan = (session.query(l2network_models.VlanID). + rvlan = (session.query(L2_MODEL.VlanID). filter_by(vlan_used=False). first()) if not rvlan: raise c_exc.VlanIDNotAvailable() - rvlanid = (session.query(l2network_models.VlanID). + rvlanid = (session.query(L2_MODEL.VlanID). filter_by(vlan_id=rvlan["vlan_id"]). one()) rvlanid["vlan_used"] = True @@ -166,7 +174,7 @@ def get_all_vlanids_used(): LOG.debug("get_all_vlanids() called") session = db.get_session() try: - vlanids = (session.query(l2network_models.VlanID). + vlanids = (session.query(L2_MODEL.VlanID). filter_by(vlan_used=True). all()) return vlanids @@ -179,7 +187,7 @@ def get_all_vlan_bindings(): LOG.debug("get_all_vlan_bindings() called") session = db.get_session() try: - bindings = (session.query(l2network_models.VlanBinding). + bindings = (session.query(L2_MODEL.VlanBinding). all()) return bindings except exc.NoResultFound: @@ -191,7 +199,7 @@ def get_vlan_binding(netid): LOG.debug("get_vlan_binding() called") session = db.get_session() try: - binding = (session.query(l2network_models.VlanBinding). + binding = (session.query(L2_MODEL.VlanBinding). filter_by(network_id=netid). one()) return binding @@ -204,13 +212,13 @@ def add_vlan_binding(vlanid, netid): LOG.debug("add_vlan_binding() called") session = db.get_session() try: - binding = (session.query(l2network_models.VlanBinding). + binding = (session.query(L2_MODEL.VlanBinding). filter_by(vlan_id=vlanid). one()) raise c_exc.NetworkVlanBindingAlreadyExists(vlan_id=vlanid, network_id=netid) except exc.NoResultFound: - binding = l2network_models.VlanBinding(vlanid, netid) + binding = L2_MODEL.VlanBinding(vlanid, netid) session.add(binding) session.flush() return binding @@ -221,7 +229,7 @@ def remove_vlan_binding(netid): LOG.debug("remove_vlan_binding() called") session = db.get_session() try: - binding = (session.query(l2network_models.VlanBinding). + binding = (session.query(L2_MODEL.VlanBinding). filter_by(network_id=netid). one()) session.delete(binding) @@ -236,7 +244,7 @@ def update_vlan_binding(netid, newvlanid=None): LOG.debug("update_vlan_binding() called") session = db.get_session() try: - binding = (session.query(l2network_models.VlanBinding). + binding = (session.query(L2_MODEL.VlanBinding). filter_by(network_id=netid). one()) if newvlanid: diff --git a/quantum/plugins/linuxbridge/db/l2network_models_v2.py b/quantum/plugins/linuxbridge/db/l2network_models_v2.py new file mode 100644 index 000000000..577f22672 --- /dev/null +++ b/quantum/plugins/linuxbridge/db/l2network_models_v2.py @@ -0,0 +1,50 @@ +# Copyright (c) 2012 OpenStack, LLC. +# +# 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 sqlalchemy import orm + +from quantum.db import model_base + + +class VlanID(model_base.BASEV2): + """Represents a vlan_id usage""" + __tablename__ = 'vlan_ids' + + vlan_id = sa.Column(sa.Integer, nullable=False, primary_key=True) + vlan_used = sa.Column(sa.Boolean, nullable=False) + + def __init__(self, vlan_id): + self.vlan_id = vlan_id + self.vlan_used = False + + def __repr__(self): + return "" % (self.vlan_id, self.vlan_used) + + +class VlanBinding(model_base.BASEV2): + """Represents a binding of vlan_id to network_id""" + __tablename__ = 'vlan_bindings' + + network_id = sa.Column(sa.String(36), sa.ForeignKey('networks.id'), + primary_key=True) + vlan_id = sa.Column(sa.Integer, nullable=False) + + def __init__(self, vlan_id, network_id): + self.vlan_id = vlan_id + self.network_id = network_id + + def __repr__(self): + return "" % (self.vlan_id, self.network_id)