]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
added network and port models similar to quantum with following changes -
authorrohitagarwalla <roagarwa@cisco.com>
Thu, 11 Aug 2011 17:39:43 +0000 (10:39 -0700)
committerrohitagarwalla <roagarwa@cisco.com>
Thu, 11 Aug 2011 17:39:43 +0000 (10:39 -0700)
 - InnoDB as storage engine to allow foreign key constraints
 - joinedLoad operation on the queries to make use of relation between Network and Port
Moved out the network and port code to make l2network contain vlanbinding, portprofile and portprofile bindings

quantum/plugins/cisco/db/api.py [new file with mode: 0644]
quantum/plugins/cisco/db/l2network_db.py
quantum/plugins/cisco/db/l2network_models.py
quantum/plugins/cisco/db/models.py [new file with mode: 0644]

diff --git a/quantum/plugins/cisco/db/api.py b/quantum/plugins/cisco/db/api.py
new file mode 100644 (file)
index 0000000..509583a
--- /dev/null
@@ -0,0 +1,254 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+# Copyright 2011 Nicira 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: Somik Behera, Nicira Networks, Inc.
+# @author: Brad Hall, Nicira Networks, Inc.
+# @author: Dan Wendlandt, Nicira Networks, Inc.
+
+from sqlalchemy import create_engine
+from sqlalchemy.orm import sessionmaker, exc, joinedload
+
+from quantum.common import exceptions as q_exc
+from quantum.plugins.cisco.db import models
+
+_ENGINE = None
+_MAKER = None
+BASE = 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(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 = models.Network(tenant_id, name)
+        session.add(net)
+        session.flush()
+        return net
+
+
+def network_list(tenant_id):
+    session = get_session()
+    return session.query(models.Network).\
+      options(joinedload(models.Network.ports)). \
+      filter_by(tenant_id=tenant_id).\
+      all()
+
+
+def network_get(net_id):
+    session = get_session()
+    try:
+        return  session.query(models.Network).\
+            options(joinedload(models.Network.ports)). \
+            filter_by(uuid=net_id).\
+            one()
+    except exc.NoResultFound, e:
+        raise q_exc.NetworkNotFound(net_id=net_id)
+
+
+def network_rename(tenant_id, net_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(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 = 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(models.Port).\
+      options(joinedload(models.Port.network)). \
+      filter_by(network_id=net_id).\
+      all()
+
+
+def port_get(net_id, port_id):
+    # confirm network exists
+    network_get(net_id)
+    session = get_session()
+    try:
+        return  session.query(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(net_id, port_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(net_id, port_id)
+    session = get_session()
+    port.state = new_state
+    session.merge(port)
+    session.flush()
+    return port
+
+
+def port_set_attachment(net_id, port_id, new_interface_id):
+    # confirm network exists
+    network_get(net_id)
+
+    session = get_session()
+    port = port_get(net_id, port_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(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(net_id, port_id):
+    # confirm network exists
+    network_get(net_id)
+
+    session = get_session()
+    port = port_get(net_id, port_id)
+    port.interface_id = None
+    session.merge(port)
+    session.flush()
+
+
+def port_destroy(net_id, port_id):
+    # confirm network exists
+    network_get(net_id)
+
+    session = get_session()
+    try:
+        port = session.query(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)
+
index ce48b42a233bb3b9982a9eba321ac0fa934c8532..bc3d7574c60d7a1d69a8ee3b02047805075f0fa0 100644 (file)
 #    under the License.
 # @author: Rohit Agarwalla, Cisco Systems, Inc.
 
+import ConfigParser
+from optparse import OptionParser
+import os
+import logging as LOG
+
 from sqlalchemy import create_engine
 from sqlalchemy.orm import sessionmaker, exc, joinedload
 
-import l2network_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
+from quantum.plugins.cisco import l2network_plugin_configuration as conf
 
+import quantum.plugins.cisco.db.api as db
 
-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()
+import l2network_models
 
 
-def port_get(port_id, net_id):
-    # confirm network exists
-    network_get(net_id)
-    session = get_session()
+CONF_FILE = "db_conn.ini"
+
+
+def find_config(basepath):
+    for root, dirs, files in os.walk(basepath):
+        if CONF_FILE in files:
+            return os.path.join(root, CONF_FILE)
+    return None
+
+
+def initialize(configfile=None):
+    config = ConfigParser.ConfigParser()
+    if configfile == None:
+        if os.path.exists(CONF_FILE):
+            configfile = CONF_FILE
+        else:
+            configfile = \
+           find_config(os.path.abspath(os.path.dirname(__file__)))
+    if configfile == None:
+        raise Exception("Configuration file \"%s\" doesn't exist" %
+              (configfile))
+    LOG.debug("Using configuration file: %s" % configfile)
+    config.read(configfile)
+
+    DB_NAME = config.get("DATABASE", "name")
+    DB_USER = config.get("DATABASE", "user")
+    DB_PASS = config.get("DATABASE", "pass")
+    DB_HOST = config.get("DATABASE", "host")
+    options = {"sql_connection": "mysql://%s:%s@%s/%s" % (DB_USER,
+    DB_PASS, DB_HOST, DB_NAME)}
+    db.configure_db(options)
+
+def prepopulate_vlan_bindings():
+    """Prepopulates the vlan_bindings table"""
+    session = db.get_session()
     try:
-        return  session.query(l2network_models.Port).\
-          filter_by(uuid=port_id).\
-          filter_by(network_id=net_id).\
-          one()
+        binding = session.query(l2network_models.VlanBinding).\
+          all()
+        raise Exception("Vlan table not empty id for prepopulation")
     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)
+        start = conf.VLAN_START
+        end = conf.VLAN_END
+        while start < end:
+            binding = l2network_models.VlanBinding(vlanid, "", 0)
+            session.add(binding)
         session.flush()
-        return port
-    except exc.NoResultFound:
-        raise q_exc.PortNotFound(port_id=port_id)
-
+    return 
 
 def get_all_vlan_bindings():
     """Lists all the vlan to network associations"""
-    session = get_session()
+    session = db.get_session()
     try:
         bindings = session.query(l2network_models.VlanBinding).\
           all()
@@ -266,7 +91,7 @@ def get_all_vlan_bindings():
 
 def get_vlan_binding(netid):
     """Lists the vlan given a network_id"""
-    session = get_session()
+    session = db.get_session()
     try:
         binding = session.query(l2network_models.VlanBinding).\
           filter_by(network_id=netid).\
@@ -278,7 +103,7 @@ def get_vlan_binding(netid):
 
 def add_vlan_binding(vlanid, vlanname, netid):
     """Adds a vlan to network association"""
-    session = get_session()
+    session = db.get_session()
     try:
         binding = session.query(l2network_models.VlanBinding).\
           filter_by(vlan_id=vlanid).\
@@ -293,7 +118,7 @@ def add_vlan_binding(vlanid, vlanname, netid):
 
 def remove_vlan_binding(netid):
     """Removes a vlan to network association"""
-    session = get_session()
+    session = db.get_session()
     try:
         binding = session.query(l2network_models.VlanBinding).\
           filter_by(network_id=netid).\
@@ -307,7 +132,7 @@ def remove_vlan_binding(netid):
 
 def update_vlan_binding(netid, newvlanid=None, newvlanname=None):
     """Updates a vlan to network association"""
-    session = get_session()
+    session = db.get_session()
     try:
         binding = session.query(l2network_models.VlanBinding).\
           filter_by(network_id=netid).\
@@ -325,7 +150,7 @@ def update_vlan_binding(netid, newvlanid=None, newvlanname=None):
 
 def get_all_portprofiles():
     """Lists all the port profiles"""
-    session = get_session()
+    session = db.get_session()
     try:
         pps = session.query(l2network_models.PortProfile).\
           all()
@@ -336,7 +161,7 @@ def get_all_portprofiles():
 
 def get_portprofile(ppid):
     """Lists a port profile"""
-    session = get_session()
+    session = db.get_session()
     try:
         pp = session.query(l2network_models.PortProfile).\
           filter_by(uuid=ppid).\
@@ -348,7 +173,7 @@ def get_portprofile(ppid):
 
 def add_portprofile(ppname, vlanid, qos):
     """Adds a port profile"""
-    session = get_session()
+    session = db.get_session()
     try:
         pp = session.query(l2network_models.PortProfile).\
           filter_by(name=ppname).\
@@ -363,7 +188,7 @@ def add_portprofile(ppname, vlanid, qos):
 
 def remove_portprofile(ppid):
     """Removes a port profile"""
-    session = get_session()
+    session = db.get_session()
     try:
         pp = session.query(l2network_models.PortProfile).\
           filter_by(uuid=ppid).\
@@ -377,7 +202,7 @@ def remove_portprofile(ppid):
 
 def update_portprofile(ppid, newppname=None, newvlanid=None, newqos=None):
     """Updates port profile"""
-    session = get_session()
+    session = db.get_session()
     try:
         pp = session.query(l2network_models.PortProfile).\
           filter_by(uuid=ppid).\
@@ -397,7 +222,7 @@ def update_portprofile(ppid, newppname=None, newvlanid=None, newqos=None):
 
 def get_all_pp_bindings():
     """Lists all the port profiles"""
-    session = get_session()
+    session = db.get_session()
     try:
         bindings = session.query(l2network_models.PortProfileBinding).\
           all()
@@ -408,7 +233,7 @@ def get_all_pp_bindings():
 
 def get_pp_binding(ppid):
     """Lists a port profile binding"""
-    session = get_session()
+    session = db.get_session()
     try:
         binding = session.query(l2network_models.PortProfileBinding).\
           filter_by(portprofile_id=ppid).\
@@ -420,7 +245,7 @@ def get_pp_binding(ppid):
 
 def add_pp_binding(tenantid, networkid, ppid, default):
     """Adds a port profile binding"""
-    session = get_session()
+    session = db.get_session()
     try:
         binding = session.query(l2network_models.PortProfileBinding).\
           filter_by(portprofile_id=ppid).\
@@ -437,7 +262,7 @@ def add_pp_binding(tenantid, networkid, ppid, default):
 
 def remove_pp_binding(ppid):
     """Removes a port profile binding"""
-    session = get_session()
+    session = db.get_session()
     try:
         binding = session.query(l2network_models.PortProfileBinding).\
           filter_by(portprofile_id=ppid).\
@@ -452,7 +277,7 @@ def remove_pp_binding(ppid):
 def update_pp_binding(ppid, newtenantid=None, newnetworkid=None, \
                                                     newdefault=None):
     """Updates port profile binding"""
-    session = get_session()
+    session = db.get_session()
     try:
         binding = session.query(l2network_models.PortProfileBinding).\
           filter_by(portprofile_id=ppid).\
index 38d93295279ca7315626b078ebf542577112b8a8..fe76c7d155b42360551866af70f2bd839c5643c2 100644 (file)
@@ -21,7 +21,8 @@ from sqlalchemy import Column, Integer, String, ForeignKey, Boolean
 from sqlalchemy.ext.declarative import declarative_base
 from sqlalchemy.orm import relation, object_mapper
 
-BASE = declarative_base()
+from quantum.plugins.cisco.db.models import BASE
+from quantum.plugins.cisco.db import models
 
 
 class L2NetworkBase(object):
@@ -60,45 +61,6 @@ class L2NetworkBase(object):
         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'
@@ -107,7 +69,7 @@ class VlanBinding(BASE, L2NetworkBase):
     vlan_name = Column(String(255))
     network_id = Column(String(255), ForeignKey("networks.uuid"), \
                         nullable=False)
-    network = relation(Network, uselist=False)
+    network = relation(models.Network, uselist=False)
 
     def __init__(self, vlan_id, vlan_name, network_id):
         self.vlan_id = vlan_id
@@ -151,7 +113,7 @@ class PortProfileBinding(BASE, L2NetworkBase):
     portprofile_id = Column(String(255), ForeignKey("portprofiles.uuid"), \
                             nullable=False)
     default = Column(Boolean)
-    network = relation(Network, uselist=False)
+    network = relation(models.Network, uselist=False)
     portprofile = relation(PortProfile, uselist=False)
 
     def __init__(self, tenant_id, network_id, portprofile_id, default):
diff --git a/quantum/plugins/cisco/db/models.py b/quantum/plugins/cisco/db/models.py
new file mode 100644 (file)
index 0000000..81ac773
--- /dev/null
@@ -0,0 +1,102 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+# Copyright 2011 Nicira 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: Somik Behera, Nicira Networks, Inc.
+# @author: Brad Hall, Nicira Networks, Inc.
+# @author: Dan Wendlandt, Nicira Networks, Inc.
+
+import uuid
+
+from sqlalchemy import Column, String, ForeignKey
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy.orm import relation, object_mapper
+
+BASE = declarative_base()
+
+
+class QuantumBase(object):
+    """Base class for Quantum 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, QuantumBase):
+    """Represents a port on a quantum network"""
+    __tablename__ = 'ports'
+
+    uuid = Column(String(255), primary_key=True)
+    network_id = Column(String(255), ForeignKey("networks.uuid"),
+                        nullable=False)
+    interface_id = Column(String(255))
+    # Port state - Hardcoding string value at the moment
+    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, QuantumBase):
+    """Represents a quantum network"""
+    __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)