- 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_ops_param_list = [{
|
||||
'param-name': 'network-name',
|
||||
'param-name': 'net-name',
|
||||
'required': True}, ]
|
||||
|
||||
_serialization_metadata = {
|
||||
|
@ -72,9 +72,10 @@ def network_create(tenant_id, name):
|
||||
net = None
|
||||
try:
|
||||
net = session.query(models.Network).\
|
||||
filter_by(name=name).\
|
||||
filter_by(name=name, tenant_id=tenant_id).\
|
||||
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:
|
||||
with session.begin():
|
||||
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)
|
||||
|
||||
|
||||
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):
|
||||
session = get_session()
|
||||
ports = None
|
||||
|
@ -26,7 +26,61 @@ from sqlalchemy.orm import relation
|
||||
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"""
|
||||
__tablename__ = 'ports'
|
||||
|
||||
@ -34,17 +88,21 @@ class Port(BASE):
|
||||
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 = uuid.uuid4()
|
||||
self.uuid = str(uuid.uuid4())
|
||||
self.network_id = network_id
|
||||
self.state = "DOWN"
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return "<Port(%s,%s,%s)>" % (self.uuid, self.network_id,
|
||||
self.interface_id)
|
||||
return "<Port(%s,%s,%s,%s)>" % (self.uuid, self.network_id,
|
||||
self.state,self.interface_id)
|
||||
|
||||
|
||||
class Network(BASE):
|
||||
class Network(BASE, QuantumBase):
|
||||
"""Represents a quantum network"""
|
||||
__tablename__ = 'networks'
|
||||
|
||||
@ -54,7 +112,7 @@ class Network(BASE):
|
||||
ports = relation(Port, order_by=Port.uuid, backref="network")
|
||||
|
||||
def __init__(self, tenant_id, name):
|
||||
self.uuid = uuid.uuid4()
|
||||
self.uuid = str(uuid.uuid4())
|
||||
self.tenant_id = tenant_id
|
||||
self.name = name
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
import logging
|
||||
|
||||
from quantum.common import exceptions as exc
|
||||
from quantum.db import api as db
|
||||
|
||||
LOG = logging.getLogger('quantum.plugins.SamplePlugin')
|
||||
|
||||
@ -258,35 +259,37 @@ class FakePlugin(object):
|
||||
'net-ports': _port_dict_2}}
|
||||
|
||||
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):
|
||||
network = FakePlugin._networks.get(network_id)
|
||||
network = db.network_get(network_id)
|
||||
if not network:
|
||||
raise exc.NetworkNotFound(net_id=network_id)
|
||||
return network
|
||||
|
||||
def _get_port(self, tenant_id, network_id, port_id):
|
||||
net = self._get_network(tenant_id, network_id)
|
||||
port = net['net-ports'].get(int(port_id))
|
||||
if not port:
|
||||
port = db.port_get(port_id)
|
||||
# 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)
|
||||
return port
|
||||
|
||||
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)
|
||||
return True
|
||||
|
||||
def _validate_attachment(self, tenant_id, network_id, port_id,
|
||||
remote_interface_id):
|
||||
network = self._get_network(tenant_id, network_id)
|
||||
for port in network['net-ports'].values():
|
||||
if port['attachment'] == remote_interface_id:
|
||||
for port in db.port_list(network_id):
|
||||
if port['interface_id'] == remote_interface_id:
|
||||
raise exc.AlreadyAttached(net_id=network_id,
|
||||
port_id=port_id,
|
||||
att_id=port['attachment'],
|
||||
att_port_id=port['port-id'])
|
||||
att_id=port['interface_id'],
|
||||
att_port_id=port['uuid'])
|
||||
|
||||
def get_all_networks(self, tenant_id):
|
||||
"""
|
||||
@ -295,14 +298,19 @@ class FakePlugin(object):
|
||||
the specified tenant.
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
retrieved a list of all the remote vifs that
|
||||
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)
|
||||
|
||||
def create_network(self, tenant_id, net_name):
|
||||
@ -311,15 +319,9 @@ class FakePlugin(object):
|
||||
a symbolic name.
|
||||
"""
|
||||
LOG.debug("FakePlugin.create_network() called")
|
||||
FakePlugin._net_counter += 1
|
||||
new_net_id = ("0" * (3 - len(str(FakePlugin._net_counter)))) + \
|
||||
str(FakePlugin._net_counter)
|
||||
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
|
||||
new_net = db.network_create(tenant_id, net_name)
|
||||
# Return uuid for newly created network as net-id.
|
||||
return {'net-id': new_net['uuid']}
|
||||
|
||||
def delete_network(self, tenant_id, net_id):
|
||||
"""
|
||||
@ -327,14 +329,14 @@ class FakePlugin(object):
|
||||
belonging to the specified tenant.
|
||||
"""
|
||||
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
|
||||
if net:
|
||||
if net['net-ports']:
|
||||
for port in net['net-ports'].values():
|
||||
if port['attachment']:
|
||||
for port in db.port_list(net_id):
|
||||
if port['interface-id']:
|
||||
raise exc.NetworkInUse(net_id=net_id)
|
||||
FakePlugin._networks.pop(net_id)
|
||||
db.network_destroy(net_id)
|
||||
return net
|
||||
# Network not found
|
||||
raise exc.NetworkNotFound(net_id=net_id)
|
||||
@ -345,8 +347,8 @@ class FakePlugin(object):
|
||||
Virtual Network.
|
||||
"""
|
||||
LOG.debug("FakePlugin.rename_network() called")
|
||||
db.network_rename(net_id, tenant_id, new_name)
|
||||
net = self._get_network(tenant_id, net_id)
|
||||
net['net-name'] = new_name
|
||||
return net
|
||||
|
||||
def get_all_ports(self, tenant_id, net_id):
|
||||
@ -355,9 +357,12 @@ class FakePlugin(object):
|
||||
specified Virtual Network.
|
||||
"""
|
||||
LOG.debug("FakePlugin.get_all_ports() called")
|
||||
network = self._get_network(tenant_id, net_id)
|
||||
ports_on_net = network['net-ports'].values()
|
||||
return ports_on_net
|
||||
port_ids = []
|
||||
ports = db.port_list(net_id)
|
||||
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):
|
||||
"""
|
||||
@ -372,30 +377,19 @@ class FakePlugin(object):
|
||||
Creates a port on the specified Virtual Network.
|
||||
"""
|
||||
LOG.debug("FakePlugin.create_port() called")
|
||||
net = self._get_network(tenant_id, net_id)
|
||||
# check port state
|
||||
# TODO(salvatore-orlando): Validate port state in API?
|
||||
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
|
||||
port = db.port_create(net_id)
|
||||
port_item = {'port-id':str(port.uuid)}
|
||||
return port_item
|
||||
|
||||
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.
|
||||
"""
|
||||
LOG.debug("FakePlugin.update_port() called")
|
||||
port=self._get_port(tenant_id, net_id, port_id)
|
||||
LOG.debug("FakePlugin.update_port() called")
|
||||
self._validate_port_state(port_state)
|
||||
port['port-state'] = port_state
|
||||
return port
|
||||
db.port_set_state(new_state)
|
||||
return
|
||||
|
||||
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,
|
||||
att_id=port['attachment'])
|
||||
try:
|
||||
net['net-ports'].pop(int(port_id))
|
||||
except KeyError:
|
||||
raise exc.PortNotFound(net_id=net_id, port_id=port_id)
|
||||
port = db.port_destroy(port_id)
|
||||
except Exception, e:
|
||||
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):
|
||||
"""
|
||||
@ -428,7 +425,7 @@ class FakePlugin(object):
|
||||
if port['attachment']:
|
||||
raise exc.PortInUse(net_id=net_id, port_id=port_id,
|
||||
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):
|
||||
"""
|
||||
@ -436,7 +433,6 @@ class FakePlugin(object):
|
||||
specified Virtual Network.
|
||||
"""
|
||||
LOG.debug("FakePlugin.unplug_interface() called")
|
||||
port = self._get_port(tenant_id, net_id, port_id)
|
||||
# TODO(salvatore-orlando):
|
||||
# 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