- Unit tests will use FakePlugin
- FakePlugin adapted to db API with sqlite - db Models updated to inherit from generic Quantum Base model (provides utility functions and capabilities for treating db objects as dicts - see nova.db.models.NovaBase) - functional tests commented out temporarily. Will un-comment when code for starting actual service is in place
This commit is contained in:
parent
d0cb0eea78
commit
a99caf43c1
@ -29,7 +29,7 @@ class Controller(common.QuantumController):
|
|||||||
""" Network API controller for Quantum API """
|
""" Network API controller for Quantum API """
|
||||||
|
|
||||||
_network_ops_param_list = [{
|
_network_ops_param_list = [{
|
||||||
'param-name': 'network-name',
|
'param-name': 'net-name',
|
||||||
'required': True}, ]
|
'required': True}, ]
|
||||||
|
|
||||||
_serialization_metadata = {
|
_serialization_metadata = {
|
||||||
|
@ -72,9 +72,10 @@ def network_create(tenant_id, name):
|
|||||||
net = None
|
net = None
|
||||||
try:
|
try:
|
||||||
net = session.query(models.Network).\
|
net = session.query(models.Network).\
|
||||||
filter_by(name=name).\
|
filter_by(name=name, tenant_id=tenant_id).\
|
||||||
one()
|
one()
|
||||||
raise Exception("Network with name \"%s\" already exists" % name)
|
raise Exception("Network with name %(name)s already " \
|
||||||
|
"exists for tenant %(tenant_id)s" % locals())
|
||||||
except exc.NoResultFound:
|
except exc.NoResultFound:
|
||||||
with session.begin():
|
with session.begin():
|
||||||
net = models.Network(tenant_id, name)
|
net = models.Network(tenant_id, name)
|
||||||
@ -154,6 +155,16 @@ def port_get(port_id):
|
|||||||
raise Exception("No port found with id = %s " % port_id)
|
raise Exception("No port found with id = %s " % port_id)
|
||||||
|
|
||||||
|
|
||||||
|
def port_set_state(port_id, new_state):
|
||||||
|
port = port_get(port_id)
|
||||||
|
if port:
|
||||||
|
session = get_session()
|
||||||
|
port.state = new_state
|
||||||
|
session.merge(port)
|
||||||
|
session.flush()
|
||||||
|
return port
|
||||||
|
|
||||||
|
|
||||||
def port_set_attachment(port_id, new_interface_id):
|
def port_set_attachment(port_id, new_interface_id):
|
||||||
session = get_session()
|
session = get_session()
|
||||||
ports = None
|
ports = None
|
||||||
|
@ -26,7 +26,61 @@ from sqlalchemy.orm import relation
|
|||||||
BASE = declarative_base()
|
BASE = declarative_base()
|
||||||
|
|
||||||
|
|
||||||
class Port(BASE):
|
class QuantumBase(object):
|
||||||
|
"""Base class for Quantum Models."""
|
||||||
|
|
||||||
|
def save(self, session=None):
|
||||||
|
"""Save this object."""
|
||||||
|
if not session:
|
||||||
|
session = get_session()
|
||||||
|
session.add(self)
|
||||||
|
try:
|
||||||
|
session.flush()
|
||||||
|
except IntegrityError, e:
|
||||||
|
if str(e).endswith('is not unique'):
|
||||||
|
raise exception.Duplicate(str(e))
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
def delete(self, session=None):
|
||||||
|
"""Delete this object."""
|
||||||
|
self.deleted = True
|
||||||
|
self.deleted_at = utils.utcnow()
|
||||||
|
self.save(session=session)
|
||||||
|
|
||||||
|
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"""
|
"""Represents a port on a quantum network"""
|
||||||
__tablename__ = 'ports'
|
__tablename__ = 'ports'
|
||||||
|
|
||||||
@ -34,17 +88,21 @@ class Port(BASE):
|
|||||||
network_id = Column(String(255), ForeignKey("networks.uuid"),
|
network_id = Column(String(255), ForeignKey("networks.uuid"),
|
||||||
nullable=False)
|
nullable=False)
|
||||||
interface_id = Column(String(255))
|
interface_id = Column(String(255))
|
||||||
|
# Port state - Hardcoding string value at the moment
|
||||||
|
state = Column(String(8))
|
||||||
|
|
||||||
def __init__(self, network_id):
|
def __init__(self, network_id):
|
||||||
self.uuid = uuid.uuid4()
|
self.uuid = str(uuid.uuid4())
|
||||||
self.network_id = network_id
|
self.network_id = network_id
|
||||||
|
self.state = "DOWN"
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Port(%s,%s,%s)>" % (self.uuid, self.network_id,
|
return "<Port(%s,%s,%s,%s)>" % (self.uuid, self.network_id,
|
||||||
self.interface_id)
|
self.state,self.interface_id)
|
||||||
|
|
||||||
|
|
||||||
class Network(BASE):
|
class Network(BASE, QuantumBase):
|
||||||
"""Represents a quantum network"""
|
"""Represents a quantum network"""
|
||||||
__tablename__ = 'networks'
|
__tablename__ = 'networks'
|
||||||
|
|
||||||
@ -54,7 +112,7 @@ class Network(BASE):
|
|||||||
ports = relation(Port, order_by=Port.uuid, backref="network")
|
ports = relation(Port, order_by=Port.uuid, backref="network")
|
||||||
|
|
||||||
def __init__(self, tenant_id, name):
|
def __init__(self, tenant_id, name):
|
||||||
self.uuid = uuid.uuid4()
|
self.uuid = str(uuid.uuid4())
|
||||||
self.tenant_id = tenant_id
|
self.tenant_id = tenant_id
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from quantum.common import exceptions as exc
|
from quantum.common import exceptions as exc
|
||||||
|
from quantum.db import api as db
|
||||||
|
|
||||||
LOG = logging.getLogger('quantum.plugins.SamplePlugin')
|
LOG = logging.getLogger('quantum.plugins.SamplePlugin')
|
||||||
|
|
||||||
@ -258,35 +259,37 @@ class FakePlugin(object):
|
|||||||
'net-ports': _port_dict_2}}
|
'net-ports': _port_dict_2}}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
FakePlugin._net_counter = len(FakePlugin._networks)
|
db_options = {"sql_connection": "sqlite:///fake_plugin.sqllite"}
|
||||||
|
db.configure_db(db_options)
|
||||||
|
FakePlugin._net_counter = 0
|
||||||
|
|
||||||
def _get_network(self, tenant_id, network_id):
|
def _get_network(self, tenant_id, network_id):
|
||||||
network = FakePlugin._networks.get(network_id)
|
network = db.network_get(network_id)
|
||||||
if not network:
|
if not network:
|
||||||
raise exc.NetworkNotFound(net_id=network_id)
|
raise exc.NetworkNotFound(net_id=network_id)
|
||||||
return network
|
return network
|
||||||
|
|
||||||
def _get_port(self, tenant_id, network_id, port_id):
|
def _get_port(self, tenant_id, network_id, port_id):
|
||||||
net = self._get_network(tenant_id, network_id)
|
net = self._get_network(tenant_id, network_id)
|
||||||
port = net['net-ports'].get(int(port_id))
|
port = db.port_get(port_id)
|
||||||
if not port:
|
# Port must exist and belong to the appropriate network.
|
||||||
|
if not port or port['network_id']!=net['uuid']:
|
||||||
raise exc.PortNotFound(net_id=network_id, port_id=port_id)
|
raise exc.PortNotFound(net_id=network_id, port_id=port_id)
|
||||||
return port
|
return port
|
||||||
|
|
||||||
def _validate_port_state(self, port_state):
|
def _validate_port_state(self, port_state):
|
||||||
if port_state.upper() not in ('UP', 'DOWN'):
|
if port_state.upper() not in ('ACTIVE', 'DOWN'):
|
||||||
raise exc.StateInvalid(port_state=port_state)
|
raise exc.StateInvalid(port_state=port_state)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _validate_attachment(self, tenant_id, network_id, port_id,
|
def _validate_attachment(self, tenant_id, network_id, port_id,
|
||||||
remote_interface_id):
|
remote_interface_id):
|
||||||
network = self._get_network(tenant_id, network_id)
|
for port in db.port_list(network_id):
|
||||||
for port in network['net-ports'].values():
|
if port['interface_id'] == remote_interface_id:
|
||||||
if port['attachment'] == remote_interface_id:
|
|
||||||
raise exc.AlreadyAttached(net_id=network_id,
|
raise exc.AlreadyAttached(net_id=network_id,
|
||||||
port_id=port_id,
|
port_id=port_id,
|
||||||
att_id=port['attachment'],
|
att_id=port['interface_id'],
|
||||||
att_port_id=port['port-id'])
|
att_port_id=port['uuid'])
|
||||||
|
|
||||||
def get_all_networks(self, tenant_id):
|
def get_all_networks(self, tenant_id):
|
||||||
"""
|
"""
|
||||||
@ -295,14 +298,19 @@ class FakePlugin(object):
|
|||||||
the specified tenant.
|
the specified tenant.
|
||||||
"""
|
"""
|
||||||
LOG.debug("FakePlugin.get_all_networks() called")
|
LOG.debug("FakePlugin.get_all_networks() called")
|
||||||
return FakePlugin._networks.values()
|
nets = []
|
||||||
|
for net in db.network_list(tenant_id):
|
||||||
|
net_item = {'net-id':str(net.uuid),
|
||||||
|
'net-name':net.name}
|
||||||
|
nets.append(net_item)
|
||||||
|
return nets
|
||||||
|
|
||||||
def get_network_details(self, tenant_id, net_id):
|
def get_network_details(self, tenant_id, net_id):
|
||||||
"""
|
"""
|
||||||
retrieved a list of all the remote vifs that
|
retrieved a list of all the remote vifs that
|
||||||
are attached to the network
|
are attached to the network
|
||||||
"""
|
"""
|
||||||
LOG.debug("get_network_details() called")
|
LOG.debug("FakePlugin.get_network_details() called")
|
||||||
return self._get_network(tenant_id, net_id)
|
return self._get_network(tenant_id, net_id)
|
||||||
|
|
||||||
def create_network(self, tenant_id, net_name):
|
def create_network(self, tenant_id, net_name):
|
||||||
@ -311,15 +319,9 @@ class FakePlugin(object):
|
|||||||
a symbolic name.
|
a symbolic name.
|
||||||
"""
|
"""
|
||||||
LOG.debug("FakePlugin.create_network() called")
|
LOG.debug("FakePlugin.create_network() called")
|
||||||
FakePlugin._net_counter += 1
|
new_net = db.network_create(tenant_id, net_name)
|
||||||
new_net_id = ("0" * (3 - len(str(FakePlugin._net_counter)))) + \
|
# Return uuid for newly created network as net-id.
|
||||||
str(FakePlugin._net_counter)
|
return {'net-id': new_net['uuid']}
|
||||||
new_net_dict = {'net-id': new_net_id,
|
|
||||||
'net-name': net_name,
|
|
||||||
'net-ports': {}}
|
|
||||||
FakePlugin._networks[new_net_id] = new_net_dict
|
|
||||||
# return network_id of the created network
|
|
||||||
return new_net_dict
|
|
||||||
|
|
||||||
def delete_network(self, tenant_id, net_id):
|
def delete_network(self, tenant_id, net_id):
|
||||||
"""
|
"""
|
||||||
@ -327,14 +329,14 @@ class FakePlugin(object):
|
|||||||
belonging to the specified tenant.
|
belonging to the specified tenant.
|
||||||
"""
|
"""
|
||||||
LOG.debug("FakePlugin.delete_network() called")
|
LOG.debug("FakePlugin.delete_network() called")
|
||||||
net = FakePlugin._networks.get(net_id)
|
net = self._get_network(tenant_id, net_id)
|
||||||
# Verify that no attachments are plugged into the network
|
# Verify that no attachments are plugged into the network
|
||||||
if net:
|
if net:
|
||||||
if net['net-ports']:
|
if net['net-ports']:
|
||||||
for port in net['net-ports'].values():
|
for port in db.port_list(net_id):
|
||||||
if port['attachment']:
|
if port['interface-id']:
|
||||||
raise exc.NetworkInUse(net_id=net_id)
|
raise exc.NetworkInUse(net_id=net_id)
|
||||||
FakePlugin._networks.pop(net_id)
|
db.network_destroy(net_id)
|
||||||
return net
|
return net
|
||||||
# Network not found
|
# Network not found
|
||||||
raise exc.NetworkNotFound(net_id=net_id)
|
raise exc.NetworkNotFound(net_id=net_id)
|
||||||
@ -345,8 +347,8 @@ class FakePlugin(object):
|
|||||||
Virtual Network.
|
Virtual Network.
|
||||||
"""
|
"""
|
||||||
LOG.debug("FakePlugin.rename_network() called")
|
LOG.debug("FakePlugin.rename_network() called")
|
||||||
|
db.network_rename(net_id, tenant_id, new_name)
|
||||||
net = self._get_network(tenant_id, net_id)
|
net = self._get_network(tenant_id, net_id)
|
||||||
net['net-name'] = new_name
|
|
||||||
return net
|
return net
|
||||||
|
|
||||||
def get_all_ports(self, tenant_id, net_id):
|
def get_all_ports(self, tenant_id, net_id):
|
||||||
@ -355,9 +357,12 @@ class FakePlugin(object):
|
|||||||
specified Virtual Network.
|
specified Virtual Network.
|
||||||
"""
|
"""
|
||||||
LOG.debug("FakePlugin.get_all_ports() called")
|
LOG.debug("FakePlugin.get_all_ports() called")
|
||||||
network = self._get_network(tenant_id, net_id)
|
port_ids = []
|
||||||
ports_on_net = network['net-ports'].values()
|
ports = db.port_list(net_id)
|
||||||
return ports_on_net
|
for x in ports:
|
||||||
|
d = {'port-id':str(x.uuid)}
|
||||||
|
port_ids.append(d)
|
||||||
|
return port_ids
|
||||||
|
|
||||||
def get_port_details(self, tenant_id, net_id, port_id):
|
def get_port_details(self, tenant_id, net_id, port_id):
|
||||||
"""
|
"""
|
||||||
@ -372,30 +377,19 @@ class FakePlugin(object):
|
|||||||
Creates a port on the specified Virtual Network.
|
Creates a port on the specified Virtual Network.
|
||||||
"""
|
"""
|
||||||
LOG.debug("FakePlugin.create_port() called")
|
LOG.debug("FakePlugin.create_port() called")
|
||||||
net = self._get_network(tenant_id, net_id)
|
port = db.port_create(net_id)
|
||||||
# check port state
|
port_item = {'port-id':str(port.uuid)}
|
||||||
# TODO(salvatore-orlando): Validate port state in API?
|
return port_item
|
||||||
self._validate_port_state(port_state)
|
|
||||||
ports = net['net-ports']
|
|
||||||
if len(ports.keys()) == 0:
|
|
||||||
new_port_id = 1
|
|
||||||
else:
|
|
||||||
new_port_id = max(ports.keys()) + 1
|
|
||||||
new_port_dict = {'port-id': new_port_id,
|
|
||||||
'port-state': port_state,
|
|
||||||
'attachment': None}
|
|
||||||
ports[new_port_id] = new_port_dict
|
|
||||||
return new_port_dict
|
|
||||||
|
|
||||||
def update_port(self, tenant_id, net_id, port_id, port_state):
|
def update_port(self, tenant_id, net_id, port_id, new_state):
|
||||||
"""
|
"""
|
||||||
Updates the state of a port on the specified Virtual Network.
|
Updates the state of a port on the specified Virtual Network.
|
||||||
"""
|
"""
|
||||||
|
port=self._get_port(tenant_id, net_id, port_id)
|
||||||
LOG.debug("FakePlugin.update_port() called")
|
LOG.debug("FakePlugin.update_port() called")
|
||||||
port = self._get_port(tenant_id, net_id, port_id)
|
|
||||||
self._validate_port_state(port_state)
|
self._validate_port_state(port_state)
|
||||||
port['port-state'] = port_state
|
db.port_set_state(new_state)
|
||||||
return port
|
return
|
||||||
|
|
||||||
def delete_port(self, tenant_id, net_id, port_id):
|
def delete_port(self, tenant_id, net_id, port_id):
|
||||||
"""
|
"""
|
||||||
@ -411,9 +405,12 @@ class FakePlugin(object):
|
|||||||
raise exc.PortInUse(net_id=net_id, port_id=port_id,
|
raise exc.PortInUse(net_id=net_id, port_id=port_id,
|
||||||
att_id=port['attachment'])
|
att_id=port['attachment'])
|
||||||
try:
|
try:
|
||||||
net['net-ports'].pop(int(port_id))
|
port = db.port_destroy(port_id)
|
||||||
except KeyError:
|
except Exception, e:
|
||||||
raise exc.PortNotFound(net_id=net_id, port_id=port_id)
|
raise Exception("Failed to delete port: %s" % str(e))
|
||||||
|
d = {}
|
||||||
|
d["port-id"] = str(port.uuid)
|
||||||
|
return d
|
||||||
|
|
||||||
def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id):
|
def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id):
|
||||||
"""
|
"""
|
||||||
@ -428,7 +425,7 @@ class FakePlugin(object):
|
|||||||
if port['attachment']:
|
if port['attachment']:
|
||||||
raise exc.PortInUse(net_id=net_id, port_id=port_id,
|
raise exc.PortInUse(net_id=net_id, port_id=port_id,
|
||||||
att_id=port['attachment'])
|
att_id=port['attachment'])
|
||||||
port['attachment'] = remote_interface_id
|
db.port_set_attachment(port_id, remote_interface_id)
|
||||||
|
|
||||||
def unplug_interface(self, tenant_id, net_id, port_id):
|
def unplug_interface(self, tenant_id, net_id, port_id):
|
||||||
"""
|
"""
|
||||||
@ -436,7 +433,6 @@ class FakePlugin(object):
|
|||||||
specified Virtual Network.
|
specified Virtual Network.
|
||||||
"""
|
"""
|
||||||
LOG.debug("FakePlugin.unplug_interface() called")
|
LOG.debug("FakePlugin.unplug_interface() called")
|
||||||
port = self._get_port(tenant_id, net_id, port_id)
|
|
||||||
# TODO(salvatore-orlando):
|
# TODO(salvatore-orlando):
|
||||||
# Should unplug on port without attachment raise an Error?
|
# Should unplug on port without attachment raise an Error?
|
||||||
port['attachment'] = None
|
db.port_set_attachment(port_id, None)
|
||||||
|
Loading…
Reference in New Issue
Block a user