Implemented quark notifications (w/ unit tests)

Notifications published on subnet creation/deletion and IP address
creation and deallocation.
This commit is contained in:
Amir Sadoughi
2013-08-08 23:39:48 -05:00
parent d887a2a93a
commit ad5fa60e45
5 changed files with 176 additions and 5 deletions

View File

@@ -21,13 +21,14 @@ import netaddr
from neutron.common import exceptions
from neutron.openstack.common import log as logging
from neutron.openstack.common.notifier import api as notifier_api
from neutron.openstack.common import timeutils
from quark.db import api as db_api
from quark.db import models
LOG = logging.getLogger("neutron")
LOG = logging.getLogger("neutron.quark.ipam")
class QuarkIpam(object):
@@ -137,13 +138,39 @@ class QuarkIpam(object):
version=subnet["ip_version"], network_id=net_id)
address["deallocated"] = 0
payload = dict(tenant_id=address["tenant_id"],
ip_block_id=address["subnet_id"],
ip_address=address["address_readable"],
device_ids=[p["device_id"] for p in address["ports"]],
created_at=address["created_at"])
notifier_api.notify(context,
notifier_api.publisher_id("network"),
"ip_block.address.create",
notifier_api.CONF.default_notification_level,
payload)
return address
def _deallocate_ip_address(self, context, address):
address["deallocated"] = 1
payload = dict(tenant_id=address["tenant_id"],
ip_block_id=address["subnet_id"],
ip_address=address["address_readable"],
device_ids=[p["device_id"] for p in address["ports"]],
created_at=address["created_at"],
deleted_at=timeutils.utcnow())
notifier_api.notify(context,
notifier_api.publisher_id("network"),
"ip_block.address.delete",
notifier_api.CONF.default_notification_level,
payload)
def deallocate_ip_address(self, context, port, **kwargs):
for addr in port["ip_addresses"]:
# Note: only deallocate ip if this is the only port mapped to it
if len(addr["ports"]) == 1:
addr["deallocated"] = 1
self._deallocate_ip_address(context, addr)
port["ip_addresses"] = []
def deallocate_mac_address(self, context, address):

View File

@@ -86,7 +86,6 @@ class Plugin(neutron_plugin_base_v2.NeutronPluginBaseV2,
neutron_session._MAKER = scoped_session(session_maker)
def __init__(self):
neutron_db_api.configure_db()
self._initDBMaker()
neutron_db_api.register_models(base=models.BASEV2)

View File

@@ -19,6 +19,9 @@ from neutron.common import config as neutron_cfg
from neutron.common import exceptions
from neutron.openstack.common import importutils
from neutron.openstack.common import log as logging
from neutron.openstack.common.notifier import api as notifier_api
from neutron.openstack.common import timeutils
from oslo.config import cfg
from quark.db import api as db_api
@@ -133,6 +136,15 @@ def create_subnet(context, subnet):
subnet_dict = v._make_subnet_dict(new_subnet,
default_route=routes.DEFAULT_ROUTE)
subnet_dict["gateway_ip"] = gateway_ip
notifier_api.notify(context,
notifier_api.publisher_id("network"),
"ip_block.create",
notifier_api.CONF.default_notification_level,
dict(tenant_id=subnet_dict["tenant_id"],
ip_block_id=subnet_dict["id"],
created_at=new_subnet["created_at"]))
return subnet_dict
@@ -283,8 +295,20 @@ def delete_subnet(context, id):
subnet = db_api.subnet_find(context, id=id, scope=db_api.ONE)
if not subnet:
raise exceptions.SubnetNotFound(subnet_id=id)
payload = dict(tenant_id=subnet["tenant_id"],
ip_block_id=subnet["id"],
created_at=subnet["created_at"],
deleted_at=timeutils.utcnow())
_delete_subnet(context, subnet)
notifier_api.notify(context,
notifier_api.publisher_id("network"),
"ip_block.delete",
notifier_api.CONF.default_notification_level,
payload)
def diagnose_subnet(context, id, fields):
if id == "*":

View File

@@ -20,6 +20,7 @@ import uuid
import mock
from neutron.api.v2 import attributes as neutron_attrs
from neutron.common import exceptions
from neutron.openstack.common.notifier import api as notifier_api
from oslo.config import cfg
from quark.db import models
@@ -694,3 +695,53 @@ class TestQuarkDeleteSubnet(test_quark_plugin.TestQuarkPlugin):
with self._stubs(subnet=subnet, ips=[{}]):
with self.assertRaises(exceptions.SubnetInUse):
self.plugin.delete_subnet(self.context, 1)
class TestSubnetsNotification(test_quark_plugin.TestQuarkPlugin):
@contextlib.contextmanager
def _stubs(self, s, deleted_at=None):
s["network"] = models.Network()
subnet = models.Subnet(**s)
db_mod = "quark.db.api"
api_mod = "neutron.openstack.common.notifier.api"
time_mod = "neutron.openstack.common.timeutils"
with contextlib.nested(
mock.patch("%s.subnet_find" % db_mod),
mock.patch("%s.network_find" % db_mod),
mock.patch("%s.subnet_create" % db_mod),
mock.patch("%s.subnet_delete" % db_mod),
mock.patch("%s.notify" % api_mod),
mock.patch("%s.utcnow" % time_mod)
) as (sub_find, net_find, sub_create, sub_del, notify, time):
sub_create.return_value = subnet
sub_find.return_value = subnet
time.return_value = deleted_at
yield notify
def test_create_subnet_notification(self):
s = dict(network_id=1, cidr="192.168.10.0/24",
tenant_id=1, id=1, created_at="123")
with self._stubs(s) as notify:
self.plugin.create_subnet(self.context, dict(subnet=s))
notify.assert_called_once_with(
self.context,
notifier_api.publisher_id("network"),
"ip_block.create",
notifier_api.CONF.default_notification_level,
dict(tenant_id=s["tenant_id"],
ip_block_id=s["id"],
created_at=s["created_at"]))
def test_delete_subnet_notification(self):
s = dict(tenant_id=1, id=1, created_at="123")
with self._stubs(s, deleted_at="456") as notify:
self.plugin.delete_subnet(self.context, 1)
notify.assert_called_once_with(
self.context,
notifier_api.publisher_id("network"),
"ip_block.delete",
notifier_api.CONF.default_notification_level,
dict(tenant_id=s["tenant_id"],
created_at=s["created_at"],
ip_block_id=s["id"],
deleted_at="456"))

View File

@@ -18,9 +18,11 @@ import mock
from neutron.common import exceptions
from neutron.db import api as neutron_db_api
from neutron.openstack.common.db.sqlalchemy import session as neutron_session
from neutron.openstack.common.notifier import api as notifier_api
from oslo.config import cfg
from quark.db import models
import quark.ipam
from quark.tests import test_base
@@ -173,8 +175,9 @@ class QuarkMacAddressDeallocation(QuarkIpamBaseTest):
class QuarkIPAddressDeallocation(QuarkIpamBaseTest):
def test_deallocate_ip_address(self):
port = dict(ip_addresses=[])
addr = dict(ports=[port])
port = dict(ip_addresses=[], device_id="foo")
addr = dict(ports=[port], tenant_id=1, subnet_id=1,
address_readable=None, created_at=None)
port["ip_addresses"].append(addr)
self.ipam.deallocate_ip_address(self.context, port)
# ORM takes care of other model if one model is modified
@@ -468,3 +471,70 @@ class TestQuarkIpPoliciesIpAllocation(QuarkIpamBaseTest):
address = self.ipam.allocate_ip_address(
self.context, 0, 0, 0, ip_address="0.0.0.240")
self.assertEqual(address["address"], 240)
class QuarkIPAddressAllocationNotifications(QuarkIpamBaseTest):
@contextlib.contextmanager
def _stubs(self, address, addresses=None, subnets=None, deleted_at=None):
address = models.IPAddress(**address)
if not addresses:
addresses = [None]
db_mod = "quark.db.api"
api_mod = "neutron.openstack.common.notifier.api"
time_mod = "neutron.openstack.common.timeutils"
with contextlib.nested(
mock.patch("%s.ip_address_find" % db_mod),
mock.patch("%s.ip_address_create" % db_mod),
mock.patch("%s.subnet_find_allocation_counts" % db_mod),
mock.patch("%s.notify" % api_mod),
mock.patch("%s.utcnow" % time_mod),
) as (addr_find, addr_create, subnet_find, notify, time):
addr_find.side_effect = addresses
addr_create.return_value = address
subnet_find.return_value = subnets
time.return_value = deleted_at
yield notify
def test_allocation_notification(self):
subnet = dict(id=1, first_ip=0, last_ip=255,
cidr="0.0.0.0/24", ip_version=4,
next_auto_assign_ip=0, network=dict(ip_policy=None),
ip_policy=None)
address = dict(tenant_id=1, address=0, created_at="123",
subnet_id=1, address_readable="0.0.0.0")
with self._stubs(
address,
subnets=[(subnet, 0)],
addresses=[None, None]
) as notify:
self.ipam.allocate_ip_address(self.context, 0, 0, 0,
version=4)
notify.assert_called_once_with(
self.context,
notifier_api.publisher_id("network"),
"ip_block.address.create",
notifier_api.CONF.default_notification_level,
dict(tenant_id=address["tenant_id"],
ip_block_id=address["subnet_id"],
ip_address="0.0.0.0",
device_ids=[],
created_at=address["created_at"]))
def test_deallocation_notification(self):
address = dict(tenant_id=1, address=0, created_at="123",
subnet_id=1, address_readable="0.0.0.0",
ports=[dict(device_id="foo")])
port = dict(ip_addresses=[address])
with self._stubs(dict(), deleted_at="456") as notify:
self.ipam.deallocate_ip_address(self.context, port)
notify.assert_called_once_with(
self.context,
notifier_api.publisher_id("network"),
"ip_block.address.delete",
notifier_api.CONF.default_notification_level,
dict(tenant_id=address["tenant_id"],
ip_block_id=address["subnet_id"],
ip_address="0.0.0.0",
device_ids=["foo"],
created_at=address["created_at"],
deleted_at="456"))