# under the License.
# @author: Rohit Agarwalla, Cisco Systems, Inc.
-from sqlalchemy.orm import exc
+from sqlalchemy import create_engine
+from sqlalchemy.orm import sessionmaker, exc, joinedload
import l2network_models
-import quantum.db.api as db
-import quantum.db.models as models
+
+
+from quantum.common import exceptions as q_exc
+
+
+_ENGINE = None
+_MAKER = None
+BASE = l2network_models.BASE
+
+
+def configure_db(options):
+ """
+ Establish the database, create an engine if needed, and
+ register the models.
+
+ :param options: Mapping of configuration options
+ """
+ global _ENGINE
+ if not _ENGINE:
+ _ENGINE = create_engine(options['sql_connection'],
+ echo=False,
+ echo_pool=True,
+ pool_recycle=3600)
+ register_models()
+
+
+def clear_db():
+ global _ENGINE
+ assert _ENGINE
+ for table in reversed(BASE.metadata.sorted_tables):
+ _ENGINE.execute(table.delete())
+
+
+def get_session(autocommit=True, expire_on_commit=False):
+ """Helper method to grab session"""
+ global _MAKER, _ENGINE
+ if not _MAKER:
+ assert _ENGINE
+ _MAKER = sessionmaker(bind=_ENGINE,
+ autocommit=autocommit,
+ expire_on_commit=expire_on_commit)
+ return _MAKER()
+
+
+def register_models():
+ """Register Models and create properties"""
+ global _ENGINE
+ assert _ENGINE
+ BASE.metadata.create_all(_ENGINE)
+
+
+def unregister_models():
+ """Unregister Models, useful clearing out data before testing"""
+ global _ENGINE
+ assert _ENGINE
+ BASE.metadata.drop_all(_ENGINE)
+
+
+def _check_duplicate_net_name(tenant_id, net_name):
+ session = get_session()
+ try:
+ net = session.query(l2network_models.Network).\
+ filter_by(tenant_id=tenant_id, name=net_name).\
+ one()
+ raise q_exc.NetworkNameExists(tenant_id=tenant_id,
+ net_name=net_name, net_id=net.uuid)
+ except exc.NoResultFound:
+ # this is the "normal" path, as API spec specifies
+ # that net-names are unique within a tenant
+ pass
+
+
+def network_create(tenant_id, name):
+ session = get_session()
+
+ _check_duplicate_net_name(tenant_id, name)
+ with session.begin():
+ net = l2network_models.Network(tenant_id, name)
+ session.add(net)
+ session.flush()
+ return net
+
+
+def network_list(tenant_id):
+ session = get_session()
+ return session.query(l2network_models.Network).\
+ options(joinedload(l2network_models.Network.ports)). \
+ filter_by(tenant_id=tenant_id).\
+ all()
+
+
+def network_get(net_id):
+ session = get_session()
+ try:
+ return session.query(l2network_models.Network).\
+ filter_by(uuid=net_id).\
+ one()
+ except exc.NoResultFound, e:
+ raise q_exc.NetworkNotFound(net_id=net_id)
+
+
+def network_rename(net_id, tenant_id, new_name):
+ session = get_session()
+ net = network_get(net_id)
+ _check_duplicate_net_name(tenant_id, new_name)
+ net.name = new_name
+ session.merge(net)
+ session.flush()
+ return net
+
+
+def network_destroy(net_id):
+ session = get_session()
+ try:
+ net = session.query(l2network_models.Network).\
+ filter_by(uuid=net_id).\
+ one()
+ session.delete(net)
+ session.flush()
+ return net
+ except exc.NoResultFound:
+ raise q_exc.NetworkNotFound(net_id=net_id)
+
+
+def port_create(net_id, state=None):
+ # confirm network exists
+ network_get(net_id)
+
+ session = get_session()
+ with session.begin():
+ port = l2network_models.Port(net_id)
+ port['state'] = state or 'DOWN'
+ session.add(port)
+ session.flush()
+ return port
+
+
+def port_list(net_id):
+ session = get_session()
+ return session.query(l2network_models.Port).\
+ options(joinedload(l2network_models.Port.network)). \
+ filter_by(network_id=net_id).\
+ all()
+
+
+def port_get(port_id, net_id):
+ # confirm network exists
+ network_get(net_id)
+ session = get_session()
+ try:
+ return session.query(l2network_models.Port).\
+ filter_by(uuid=port_id).\
+ filter_by(network_id=net_id).\
+ one()
+ except exc.NoResultFound:
+ raise q_exc.PortNotFound(net_id=net_id, port_id=port_id)
+
+
+def port_set_state(port_id, net_id, new_state):
+ if new_state not in ('ACTIVE', 'DOWN'):
+ raise q_exc.StateInvalid(port_state=new_state)
+
+ # confirm network exists
+ network_get(net_id)
+
+ port = port_get(port_id, net_id)
+ session = get_session()
+ port.state = new_state
+ session.merge(port)
+ session.flush()
+ return port
+
+
+def port_set_attachment(port_id, net_id, new_interface_id):
+ # confirm network exists
+ network_get(net_id)
+
+ session = get_session()
+ port = port_get(port_id, net_id)
+
+ if new_interface_id != "":
+ # We are setting, not clearing, the attachment-id
+ if port['interface_id']:
+ raise q_exc.PortInUse(net_id=net_id, port_id=port_id,
+ att_id=port['interface_id'])
+
+ try:
+ port = session.query(l2network_models.Port).\
+ filter_by(interface_id=new_interface_id).\
+ one()
+ raise q_exc.AlreadyAttached(net_id=net_id,
+ port_id=port_id,
+ att_id=new_interface_id,
+ att_port_id=port['uuid'])
+ except exc.NoResultFound:
+ # this is what should happen
+ pass
+ port.interface_id = new_interface_id
+ session.merge(port)
+ session.flush()
+ return port
+
+
+def port_unset_attachment(port_id, net_id):
+ # confirm network exists
+ network_get(net_id)
+
+ session = get_session()
+ port = port_get(port_id, net_id)
+ port.interface_id = None
+ session.merge(port)
+ session.flush()
+
+
+def port_destroy(port_id, net_id):
+ # confirm network exists
+ network_get(net_id)
+
+ session = get_session()
+ try:
+ port = session.query(l2network_models.Port).\
+ filter_by(uuid=port_id).\
+ filter_by(network_id=net_id).\
+ one()
+ if port['interface_id']:
+ raise q_exc.PortInUse(net_id=net_id, port_id=port_id,
+ att_id=port['interface_id'])
+ session.delete(port)
+ session.flush()
+ return port
+ except exc.NoResultFound:
+ raise q_exc.PortNotFound(port_id=port_id)
def get_all_vlan_bindings():
"""Lists all the vlan to network associations"""
- session = db.get_session()
+ session = get_session()
try:
bindings = session.query(l2network_models.VlanBinding).\
all()
def get_vlan_binding(netid):
"""Lists the vlan given a network_id"""
- session = db.get_session()
+ session = get_session()
try:
binding = session.query(l2network_models.VlanBinding).\
filter_by(network_id=netid).\
def add_vlan_binding(vlanid, vlanname, netid):
"""Adds a vlan to network association"""
- session = db.get_session()
+ session = get_session()
try:
binding = session.query(l2network_models.VlanBinding).\
filter_by(vlan_id=vlanid).\
def remove_vlan_binding(netid):
"""Removes a vlan to network association"""
- session = db.get_session()
+ session = get_session()
try:
binding = session.query(l2network_models.VlanBinding).\
filter_by(network_id=netid).\
def update_vlan_binding(netid, newvlanid=None, newvlanname=None):
"""Updates a vlan to network association"""
- session = db.get_session()
+ session = get_session()
try:
binding = session.query(l2network_models.VlanBinding).\
filter_by(network_id=netid).\
one()
if newvlanid:
- binding.vlan_id = newvlanid
+ binding["vlan_id"] = newvlanid
if newvlanname:
- binding.vlan_name = newvlanname
+ binding["vlan_name"] = newvlanname
session.merge(binding)
session.flush()
return binding
def get_all_portprofiles():
"""Lists all the port profiles"""
- session = db.get_session()
+ session = get_session()
try:
pps = session.query(l2network_models.PortProfile).\
all()
def get_portprofile(ppid):
"""Lists a port profile"""
- session = db.get_session()
+ session = get_session()
try:
pp = session.query(l2network_models.PortProfile).\
filter_by(uuid=ppid).\
def add_portprofile(ppname, vlanid, qos):
"""Adds a port profile"""
- session = db.get_session()
+ session = get_session()
try:
pp = session.query(l2network_models.PortProfile).\
filter_by(name=ppname).\
def remove_portprofile(ppid):
"""Removes a port profile"""
- session = db.get_session()
+ session = get_session()
try:
pp = session.query(l2network_models.PortProfile).\
filter_by(uuid=ppid).\
def update_portprofile(ppid, newppname=None, newvlanid=None, newqos=None):
"""Updates port profile"""
- session = db.get_session()
+ session = get_session()
try:
pp = session.query(l2network_models.PortProfile).\
filter_by(uuid=ppid).\
one()
if newppname:
- pp.name = newppname
+ pp["name"] = newppname
if newvlanid:
- pp.vlan_id = newvlanid
+ pp["vlan_id"] = newvlanid
if newqos:
- pp.qos = newqos
+ pp["qos"] = newqos
session.merge(pp)
session.flush()
return pp
def get_all_pp_bindings():
"""Lists all the port profiles"""
- session = db.get_session()
+ session = get_session()
try:
bindings = session.query(l2network_models.PortProfileBinding).\
all()
def get_pp_binding(ppid):
"""Lists a port profile binding"""
- session = db.get_session()
+ session = get_session()
try:
binding = session.query(l2network_models.PortProfileBinding).\
filter_by(portprofile_id=ppid).\
def add_pp_binding(tenantid, networkid, ppid, default):
"""Adds a port profile binding"""
- session = db.get_session()
+ session = get_session()
try:
binding = session.query(l2network_models.PortProfileBinding).\
filter_by(portprofile_id=ppid).\
def remove_pp_binding(ppid):
"""Removes a port profile binding"""
- session = db.get_session()
+ session = get_session()
try:
binding = session.query(l2network_models.PortProfileBinding).\
filter_by(portprofile_id=ppid).\
def update_pp_binding(ppid, newtenantid=None, newnetworkid=None, \
newdefault=None):
"""Updates port profile binding"""
- session = db.get_session()
+ session = get_session()
try:
binding = session.query(l2network_models.PortProfileBinding).\
filter_by(portprofile_id=ppid).\
one()
if newtenantid:
- binding.tenant_id = newtenantid
+ binding["tenant_id"] = newtenantid
if newnetworkid:
- binding.network_id = newnetworkid
+ binding["network_id"] = newnetworkid
if newdefault:
- binding.default = newdefault
+ binding["default"] = newdefault
session.merge(binding)
session.flush()
return binding
import uuid
from sqlalchemy import Column, Integer, String, ForeignKey, Boolean
-from sqlalchemy.orm import relation
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy.orm import relation, object_mapper
-from quantum.db.models import BASE
+BASE = declarative_base()
-class VlanBinding(BASE):
+class L2NetworkBase(object):
+ """Base class for L2Network Models."""
+ __table_args__ = {'mysql_engine': 'InnoDB'}
+
+ def __setitem__(self, key, value):
+ setattr(self, key, value)
+
+ def __getitem__(self, key):
+ return getattr(self, key)
+
+ def get(self, key, default=None):
+ return getattr(self, key, default)
+
+ def __iter__(self):
+ self._i = iter(object_mapper(self).columns)
+ return self
+
+ def next(self):
+ n = self._i.next().name
+ return n, getattr(self, n)
+
+ def update(self, values):
+ """Make the model object behave like a dict"""
+ for k, v in values.iteritems():
+ setattr(self, k, v)
+
+ def iteritems(self):
+ """Make the model object behave like a dict.
+ Includes attributes from joins."""
+ local = dict(self)
+ joined = dict([(k, v) for k, v in self.__dict__.iteritems()
+ if not k[0] == '_'])
+ local.update(joined)
+ return local.iteritems()
+
+
+class Port(BASE, L2NetworkBase):
+ """Represents a port on a l2network plugin"""
+ __tablename__ = 'ports'
+
+ uuid = Column(String(255), primary_key=True)
+ network_id = Column(String(255), ForeignKey("networks.uuid"),
+ nullable=False)
+ interface_id = Column(String(255))
+ state = Column(String(8))
+
+ def __init__(self, network_id):
+ self.uuid = str(uuid.uuid4())
+ self.network_id = network_id
+ self.state = "DOWN"
+
+ def __repr__(self):
+ return "<Port(%s,%s,%s,%s)>" % (self.uuid, self.network_id,
+ self.state, self.interface_id)
+
+
+class Network(BASE, L2NetworkBase):
+ """Represents a networ on l2network plugin"""
+ __tablename__ = 'networks'
+
+ uuid = Column(String(255), primary_key=True)
+ tenant_id = Column(String(255), nullable=False)
+ name = Column(String(255))
+ ports = relation(Port, order_by=Port.uuid, backref="network")
+
+ def __init__(self, tenant_id, name):
+ self.uuid = str(uuid.uuid4())
+ self.tenant_id = tenant_id
+ self.name = name
+
+ def __repr__(self):
+ return "<Network(%s,%s,%s)>" % \
+ (self.uuid, self.name, self.tenant_id)
+
+
+class VlanBinding(BASE, L2NetworkBase):
"""Represents a binding of vlan_id to network_id"""
__tablename__ = 'vlan_bindings'
vlan_id = Column(Integer, primary_key=True)
vlan_name = Column(String(255))
- network_id = Column(String(255), nullable=False)
- #foreign key to networks.uuid
+ network_id = Column(String(255), ForeignKey("networks.uuid"), \
+ nullable=False)
+ network = relation(Network, uselist=False)
def __init__(self, vlan_id, vlan_name, network_id):
self.vlan_id = vlan_id
(self.vlan_id, self.vlan_name, self.network_id)
-class PortProfile(BASE):
+class PortProfile(BASE, L2NetworkBase):
"""Represents L2 network plugin level PortProfile for a network"""
__tablename__ = 'portprofiles'
(self.uuid, self.name, self.vlan_id, self.qos)
-class PortProfileBinding(BASE):
+class PortProfileBinding(BASE, L2NetworkBase):
"""Represents PortProfile binding to tenant and network"""
__tablename__ = 'portprofile_bindings'
id = Column(Integer, primary_key=True, autoincrement=True)
tenant_id = Column(String(255))
- network_id = Column(String(255), nullable=False)
- #foreign key to networks.uuid
- portprofile_id = Column(String(255), nullable=False)
- #foreign key to portprofiles.uuid
+ network_id = Column(String(255), ForeignKey("networks.uuid"), \
+ nullable=False)
+ portprofile_id = Column(String(255), ForeignKey("portprofiles.uuid"), \
+ nullable=False)
default = Column(Boolean)
+ network = relation(Network, uselist=False)
+ portprofile = relation(PortProfile, uselist=False)
def __init__(self, tenant_id, network_id, portprofile_id, default):
self.tenant_id = tenant_id