Implemented quark notifications (w/ unit tests)
Notifications published on subnet creation/deletion and IP address creation and deallocation.
This commit is contained in:
@@ -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):
|
||||
|
@@ -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)
|
||||
|
@@ -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 == "*":
|
||||
|
@@ -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"))
|
||||
|
@@ -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"))
|
||||
|
Reference in New Issue
Block a user