Implemented DELETE and GET /mac_address_ranges/<uuid>

* Added exceptions.MacAddressRangeNotFound,
  exceptions.MacAddressRangeInUse
* Implemented tests for plugin.get_mac_address_range
* Implemented tests for plugin.delete_mac_address_range
This commit is contained in:
Amir Sadoughi
2013-05-16 02:20:01 -05:00
parent e583cc95ae
commit c036f5186d
6 changed files with 114 additions and 7 deletions

View File

@@ -61,10 +61,12 @@ class MacAddressRangesController(wsgi.Controller):
def show(self, request, id):
context = request.context
tenant_id = id
if not tenant_id:
raise webob.exc.HTTPBadRequest('invalid tenant')
return self._plugin.get_mac_address_range(context, id)
return {"mac_address_range":
self._plugin.get_mac_address_range(context, id)}
def delete(self, request, id, **kwargs):
context = request.context
return self._plugin.delete_mac_address_range(context, id)
class Mac_address_ranges(object):

View File

@@ -252,6 +252,10 @@ def mac_address_range_create(context, **range_dict):
return new_range
def mac_address_range_delete(context, mac_address_range):
context.session.delete(mac_address_range)
def mac_address_update(context, mac, **kwargs):
mac.update(kwargs)
context.session.add(mac)

View File

@@ -306,7 +306,8 @@ class MacAddress(BASEV2, models.HasTenant):
__tablename__ = "quark_mac_addresses"
address = sa.Column(sa.BigInteger(), primary_key=True)
mac_address_range_id = sa.Column(
sa.String(36), sa.ForeignKey("quark_mac_address_ranges.id"),
sa.String(36),
sa.ForeignKey("quark_mac_address_ranges.id", ondelete="CASCADE"),
nullable=False)
deallocated = sa.Column(sa.Boolean())
deallocated_at = sa.Column(sa.DateTime())
@@ -319,6 +320,11 @@ class MacAddressRange(BASEV2, models.HasId):
first_address = sa.Column(sa.BigInteger(), nullable=False)
last_address = sa.Column(sa.BigInteger(), nullable=False)
next_auto_assign_mac = sa.Column(sa.BigInteger(), nullable=False)
allocated_macs = orm.relationship(MacAddress,
primaryjoin='and_(MacAddressRange.id=='
'MacAddress.mac_address_range_id, '
'MacAddress.deallocated!=1)',
backref="mac_address_range")
class Network(BASEV2, models.HasTenant, models.HasId):

View File

@@ -5,6 +5,14 @@ class InvalidMacAddressRange(exceptions.QuantumException):
message = _("Invalid MAC address range %(cidr)s.")
class MacAddressRangeNotFound(exceptions.NotFound):
message = _("MAC address range %(mac_address_range_id) not found.")
class MacAddressRangeInUse(exceptions.InUse):
message = _("MAC address range %(mac_address_range_id) in use.")
class RouteNotFound(exceptions.NotFound):
message = _("Route %(route_id)s not found.")

View File

@@ -893,6 +893,27 @@ class Plugin(quantum_plugin_base_v2.QuantumPluginBaseV2,
return self._make_port_dict(port)
def get_mac_address_range(self, context, id, fields=None):
"""Retrieve a mac_address_range.
: param context: quantum api request context
: param id: UUID representing the network to fetch.
: param fields: a list of strings that are valid keys in a
network dictionary as listed in the RESOURCE_ATTRIBUTE_MAP
object in quantum/api/v2/attributes.py. Only these fields
will be returned.
"""
LOG.info("get_mac_address_range %s for tenant %s fields %s" %
(id, context.tenant_id, fields))
mac_address_range = db_api.mac_address_range_find(
context, id=id, scope=db_api.ONE)
if not mac_address_range:
raise quark_exceptions.MacAddressRangeNotFound(
mac_address_range_id=id)
return self._make_mac_range_dict(mac_address_range)
def get_mac_address_ranges(self, context):
LOG.info("get_mac_address_ranges for tenant %s" % context.tenant_id)
ranges = db_api.mac_address_range_find(context)
@@ -930,6 +951,26 @@ class Plugin(quantum_plugin_base_v2.QuantumPluginBaseV2,
prefix_int = int(prefix, base=16)
return cidr, prefix_int, prefix_int + mask_size
def _delete_mac_address_range(self, context, mac_address_range):
if mac_address_range.allocated_macs:
raise quark_exceptions.MacAddressRangeInUse(
mac_address_range_id=mac_address_range["id"])
db_api.mac_address_range_delete(context, mac_address_range)
def delete_mac_address_range(self, context, id):
"""Delete a mac_address_range.
: param context: quantum api request context
: param id: UUID representing the mac_address_range to delete.
"""
LOG.info("delete_mac_address_range %s for tenant %s" %
(id, context.tenant_id))
mar = db_api.mac_address_range_find(context, id=id, scope=db_api.ONE)
if not mar:
raise quark_exceptions.MacAddressRangeNotFound(
mac_address_range_id=id)
self._delete_mac_address_range(context, mar)
def get_route(self, context, id):
LOG.info("get_route %s for tenant %s" % (id, context.tenant_id))
route = db_api.route_find(context, id=id)

View File

@@ -1466,16 +1466,28 @@ class TestQuarkGetMacAddressRanges(TestQuarkPlugin):
def _stubs(self, mac_range):
db_mod = "quark.db.api"
with mock.patch("%s.mac_address_range_find" % db_mod) as mar_find:
mar_find.return_value = [mac_range]
mar_find.return_value = mac_range
yield
def test_find_mac_ranges(self):
mar = dict(id=1, cidr="AA:BB:CC/24")
with self._stubs(mar):
with self._stubs([mar]):
res = self.plugin.get_mac_address_ranges(self.context)
self.assertEqual(res[0]["id"], mar["id"])
self.assertEqual(res[0]["cidr"], mar["cidr"])
def test_find_mac_range(self):
mar = dict(id=1, cidr="AA:BB:CC/24")
with self._stubs(mar):
res = self.plugin.get_mac_address_range(self.context, 1)
self.assertEqual(res["id"], mar["id"])
self.assertEqual(res["cidr"], mar["cidr"])
def test_find_mac_range_fail(self):
with self._stubs(None):
with self.assertRaises(quark_exceptions.MacAddressRangeNotFound):
self.plugin.get_mac_address_range(self.context, 1)
class TestQuarkCreateMacAddressRanges(TestQuarkPlugin):
@contextlib.contextmanager
@@ -1537,6 +1549,40 @@ class TestQuarkCreateMacAddressRanges(TestQuarkPlugin):
cidr, first, last = self.plugin._to_mac_range("F0-0-BAR")
class TestQuarkDeleteMacAddressRanges(TestQuarkPlugin):
@contextlib.contextmanager
def _stubs(self, mac_range):
db_mod = "quark.db.api"
with contextlib.nested(
mock.patch("%s.mac_address_range_find" % db_mod),
mock.patch("%s.mac_address_range_delete" % db_mod),
) as (mar_find, mar_delete):
mar_find.return_value = mac_range
yield mar_delete
def test_mac_address_range_delete_not_found(self):
with self._stubs(None):
with self.assertRaises(quark_exceptions.MacAddressRangeNotFound):
self.plugin.delete_mac_address_range(self.context, 1)
def test_mac_address_range_delete_in_use(self):
mar = mock.MagicMock()
mar.id = 1
mar.allocated_macs = 1
with self._stubs(mar):
with self.assertRaises(quark_exceptions.MacAddressRangeInUse):
self.plugin.delete_mac_address_range(self.context, 1)
def test_mac_address_range_delete_success(self):
mar = mock.MagicMock()
mar.id = 1
mar.allocated_macs = 0
with self._stubs(mar) as mar_delete:
resp = self.plugin.delete_mac_address_range(self.context, 1)
self.assertIsNone(resp)
mar_delete.assert_called_once_with(self.context, mar)
class TestQuarkGetRoutes(TestQuarkPlugin):
@contextlib.contextmanager
def _stubs(self, routes):