vmware-nsx/quantum/plugins/linuxbridge/db/l2network_db.py
Gary Kotton 58d42b6558 RPC support for Linux Bridge Plugin and Agent
blueprint scalable-agent-comms

This is the first stage of the blueprint. This adds support to the linux bridge
plugin.

The development followed the design described in:
https://docs.google.com/document/d/1MbcBA2Os4b98ybdgAw2qe_68R1NG6KMh8zdZKgOlpvg/edit?pli=1

Change-Id: I4004c05a63ce49f020c2016c8763e73238b465a7
2012-08-08 10:09:47 -04:00

314 lines
9.9 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012, Cisco Systems, Inc.
#
# 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: Rohit Agarwalla, Cisco Systems, Inc.
import logging
from sqlalchemy import func
from sqlalchemy.orm import exc
from quantum.api import api_common
from quantum.common import exceptions as q_exc
import quantum.db.api as db
from quantum.db import models_v2
from quantum.openstack.common import cfg
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__)
# The global variable for the database version model
L2_MODEL = l2network_models
def initialize(base=None):
global L2_MODEL
options = {"sql_connection": "%s" % cfg.CONF.DATABASE.sql_connection}
options.update({"sql_max_retries": cfg.CONF.DATABASE.sql_max_retries})
options.update({"reconnect_interval":
cfg.CONF.DATABASE.reconnect_interval})
if base:
options.update({"base": base})
L2_MODEL = l2network_models_v2
db.configure_db(options)
create_vlanids()
def create_vlanids():
"""Prepopulate the vlan_bindings table"""
LOG.debug("create_vlanids() called")
session = db.get_session()
start = cfg.CONF.VLANS.vlan_start
end = cfg.CONF.VLANS.vlan_end
try:
vlanid = session.query(L2_MODEL.VlanID).one()
except exc.MultipleResultsFound:
"""
TODO (Sumit): Salvatore rightly points out that this will not handle
change in VLAN ID range across server reboots. This is currently not
a supported feature. This logic will need to change if this feature
has to be supported.
Per Dan's suggestion we just throw a server exception for now.
"""
current_start = (
int(session.query(func.min(L2_MODEL.VlanID.vlan_id)).
one()[0]))
current_end = (
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))
LOG.debug("New VLAN range %s-%s" % (start, end))
raise c_exc.UnableToChangeVlanRange(range_start=current_start,
range_end=current_end)
except exc.NoResultFound:
LOG.debug("Setting VLAN range to %s-%s" % (start, end))
while start <= end:
vlanid = L2_MODEL.VlanID(start)
session.add(vlanid)
start += 1
session.flush()
return
def get_all_vlanids():
"""Get all the vlanids"""
LOG.debug("get_all_vlanids() called")
session = db.get_session()
try:
vlanids = (session.query(L2_MODEL.VlanID).
all())
return vlanids
except exc.NoResultFound:
return []
def is_vlanid_used(vlan_id):
"""Check if a vlanid is in use"""
LOG.debug("is_vlanid_used() called")
session = db.get_session()
try:
vlanid = (session.query(L2_MODEL.VlanID).
filter_by(vlan_id=vlan_id).
one())
return vlanid["vlan_used"]
except exc.NoResultFound:
raise c_exc.VlanIDNotFound(vlan_id=vlan_id)
def release_vlanid(vlan_id):
"""Set the vlanid state to be unused, and delete if not in range"""
LOG.debug("release_vlanid() called")
session = db.get_session()
try:
vlanid = (session.query(L2_MODEL.VlanID).
filter_by(vlan_id=vlan_id).
one())
vlanid["vlan_used"] = False
if (vlan_id >= cfg.CONF.VLANS.vlan_start and
vlan_id <= cfg.CONF.VLANS.vlan_end):
session.merge(vlanid)
else:
session.delete(vlanid)
session.flush()
return vlanid["vlan_used"]
except exc.NoResultFound:
raise c_exc.VlanIDNotFound(vlan_id=vlan_id)
return
def delete_vlanid(vlan_id):
"""Delete a vlanid entry from db"""
LOG.debug("delete_vlanid() called")
session = db.get_session()
try:
vlanid = (session.query(L2_MODEL.VlanID).
filter_by(vlan_id=vlan_id).
one())
session.delete(vlanid)
session.flush()
return vlanid
except exc.NoResultFound:
raise c_exc.VlanIDNotFound(vlan_id=vlan_id)
def reserve_vlanid():
"""Reserve the first unused vlanid"""
LOG.debug("reserve_vlanid() called")
session = db.get_session()
try:
rvlan = (session.query(L2_MODEL.VlanID).
first())
if not rvlan:
create_vlanids()
rvlan = (session.query(L2_MODEL.VlanID).
filter_by(vlan_used=False).
first())
if not rvlan:
raise c_exc.VlanIDNotAvailable()
rvlanid = (session.query(L2_MODEL.VlanID).
filter_by(vlan_id=rvlan["vlan_id"]).
one())
rvlanid["vlan_used"] = True
session.merge(rvlanid)
session.flush()
return rvlan["vlan_id"]
except exc.NoResultFound:
raise c_exc.VlanIDNotAvailable()
def reserve_specific_vlanid(vlan_id):
"""Reserve a specific vlanid"""
LOG.debug("reserve_specific_vlanid() called")
if vlan_id < 1 or vlan_id > 4094:
msg = _("Specified VLAN %s outside legal range (1-4094)") % vlan_id
raise q_exc.InvalidInput(error_message=msg)
session = db.get_session()
try:
rvlanid = (session.query(l2network_models.VlanID).
filter_by(vlan_id=vlan_id).
one())
if rvlanid["vlan_used"]:
raise q_exc.VlanIdInUse(vlan_id=vlan_id)
LOG.debug("reserving dynamic vlanid %s" % vlan_id)
rvlanid["vlan_used"] = True
session.merge(rvlanid)
except exc.NoResultFound:
rvlanid = l2network_models.VlanID(vlan_id)
LOG.debug("reserving non-dynamic vlanid %s" % vlan_id)
rvlanid["vlan_used"] = True
session.add(rvlanid)
session.flush()
def get_all_vlanids_used():
"""Get all the vlanids used"""
LOG.debug("get_all_vlanids() called")
session = db.get_session()
try:
vlanids = (session.query(L2_MODEL.VlanID).
filter_by(vlan_used=True).
all())
return vlanids
except exc.NoResultFound:
return []
def get_all_vlan_bindings():
"""List all the vlan to network associations"""
LOG.debug("get_all_vlan_bindings() called")
session = db.get_session()
try:
bindings = (session.query(L2_MODEL.VlanBinding).
all())
return bindings
except exc.NoResultFound:
return []
def get_vlan_binding(netid):
"""List the vlan given a network_id"""
LOG.debug("get_vlan_binding() called")
session = db.get_session()
try:
binding = (session.query(L2_MODEL.VlanBinding).
filter_by(network_id=netid).
one())
return binding
except exc.NoResultFound:
raise c_exc.NetworkVlanBindingNotFound(network_id=netid)
def add_vlan_binding(vlanid, netid):
"""Add a vlan to network association"""
LOG.debug("add_vlan_binding() called")
session = db.get_session()
try:
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 = L2_MODEL.VlanBinding(vlanid, netid)
session.add(binding)
session.flush()
return binding
def remove_vlan_binding(netid):
"""Remove a vlan to network association"""
LOG.debug("remove_vlan_binding() called")
session = db.get_session()
try:
binding = (session.query(L2_MODEL.VlanBinding).
filter_by(network_id=netid).
one())
session.delete(binding)
session.flush()
return binding
except exc.NoResultFound:
pass
def update_vlan_binding(netid, newvlanid=None):
"""Update a vlan to network association"""
LOG.debug("update_vlan_binding() called")
session = db.get_session()
try:
binding = (session.query(L2_MODEL.VlanBinding).
filter_by(network_id=netid).
one())
if newvlanid:
binding["vlan_id"] = newvlanid
session.merge(binding)
session.flush()
return binding
except exc.NoResultFound:
raise q_exc.NetworkNotFound(net_id=netid)
def get_port_from_device(device):
"""Get port from database"""
LOG.debug("get_port_from_device() called")
session = db.get_session()
ports = session.query(models_v2.Port).all()
if not ports:
return
for port in ports:
if port['id'].startswith(device):
return port
return
def set_port_status(port_id, status):
"""Set the port status"""
LOG.debug("set_port_status as %s called", status)
session = db.get_session()
try:
port = session.query(models_v2.Port).filter_by(id=port_id).one()
port['status'] = status
if status == api_common.OperationalStatus.DOWN:
port['device_id'] = ''
session.merge(port)
session.flush()
except exc.NoResultFound:
raise q_exc.PortNotFound(port_id=port_id)