Fixes #75
IP addresses in subnets marked as "do_not_use" are now ignored successfully.
This commit is contained in:
@@ -267,6 +267,10 @@ def ip_address_find(context, lock_mode=False, **filters):
|
|||||||
query = query.filter(stmt.c.ports_count <= 1)
|
query = query.filter(stmt.c.ports_count <= 1)
|
||||||
|
|
||||||
model_filters = _model_query(context, models.IPAddress, filters)
|
model_filters = _model_query(context, models.IPAddress, filters)
|
||||||
|
if "do_not_use" in filters:
|
||||||
|
query = query.filter(models.Subnet.do_not_use ==
|
||||||
|
filters["do_not_use"])
|
||||||
|
|
||||||
if filters.get("device_id"):
|
if filters.get("device_id"):
|
||||||
model_filters.append(models.IPAddress.ports.any(
|
model_filters.append(models.IPAddress.ports.any(
|
||||||
models.Port.device_id.in_(filters["device_id"])))
|
models.Port.device_id.in_(filters["device_id"])))
|
||||||
|
|||||||
@@ -196,7 +196,8 @@ class QuarkIpam(object):
|
|||||||
"network_id": net_id, "reuse_after": reuse_after,
|
"network_id": net_id, "reuse_after": reuse_after,
|
||||||
"deallocated": True, "scope": db_api.ONE,
|
"deallocated": True, "scope": db_api.ONE,
|
||||||
"ip_address": ip_address, "lock_mode": True,
|
"ip_address": ip_address, "lock_mode": True,
|
||||||
"version": version, "order_by": "address"}
|
"version": version, "order_by": "address",
|
||||||
|
"do_not_use": False}
|
||||||
|
|
||||||
if sub_ids:
|
if sub_ids:
|
||||||
ip_kwargs["subnet_id"] = sub_ids
|
ip_kwargs["subnet_id"] = sub_ids
|
||||||
|
|||||||
@@ -14,10 +14,13 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import datetime
|
||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
|
from neutron.common import exceptions
|
||||||
from neutron import context
|
from neutron import context
|
||||||
from neutron.db import api as neutron_db_api
|
from neutron.db import api as neutron_db_api
|
||||||
|
from neutron.openstack.common import timeutils
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
import unittest2
|
import unittest2
|
||||||
|
|
||||||
@@ -74,6 +77,73 @@ class QuarkIPAddressAllocate(QuarkIpamBaseFunctionalTest):
|
|||||||
self.assertEqual(ipaddress[0]['used_by_tenant_id'], "fake")
|
self.assertEqual(ipaddress[0]['used_by_tenant_id'], "fake")
|
||||||
|
|
||||||
|
|
||||||
|
class QuarkIPAddressReallocate(QuarkIpamBaseFunctionalTest):
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def _stubs(self, network, subnet, address):
|
||||||
|
self.ipam = quark.ipam.QuarkIpamANY()
|
||||||
|
with self.context.session.begin():
|
||||||
|
next_ip = subnet.pop("next_auto_assign_ip", 0)
|
||||||
|
net_mod = db_api.network_create(self.context, **network)
|
||||||
|
subnet["network"] = net_mod
|
||||||
|
sub_mod = db_api.subnet_create(self.context, **subnet)
|
||||||
|
|
||||||
|
address["network_id"] = net_mod["id"]
|
||||||
|
address["subnet_id"] = sub_mod["id"]
|
||||||
|
ip = db_api.ip_address_create(self.context, **address)
|
||||||
|
address.pop("address")
|
||||||
|
db_api.ip_address_update(self.context, ip, **address)
|
||||||
|
|
||||||
|
# NOTE(asadoughi): update after cidr constructor has been invoked
|
||||||
|
db_api.subnet_update(self.context,
|
||||||
|
sub_mod,
|
||||||
|
next_auto_assign_ip=next_ip)
|
||||||
|
yield net_mod
|
||||||
|
|
||||||
|
def test_allocate_finds_ip_reallocates(self):
|
||||||
|
network = dict(name="public", tenant_id="fake")
|
||||||
|
ipnet = netaddr.IPNetwork("0.0.0.0/24")
|
||||||
|
next_ip = ipnet.ipv6().first + 10
|
||||||
|
subnet = dict(cidr="0.0.0.0/24", next_auto_assign_ip=next_ip,
|
||||||
|
ip_policy=None, tenant_id="fake", do_not_use=False)
|
||||||
|
|
||||||
|
addr = netaddr.IPAddress("0.0.0.2")
|
||||||
|
|
||||||
|
after_reuse_after = cfg.CONF.QUARK.ipam_reuse_after + 1
|
||||||
|
reusable_after = datetime.timedelta(seconds=after_reuse_after)
|
||||||
|
deallocated_at = timeutils.utcnow() - reusable_after
|
||||||
|
ip_address = dict(address=addr, version=4, _deallocated=True,
|
||||||
|
deallocated_at=deallocated_at)
|
||||||
|
|
||||||
|
with self._stubs(network, subnet, ip_address) as net:
|
||||||
|
ipaddress = []
|
||||||
|
self.ipam.allocate_ip_address(self.context, ipaddress,
|
||||||
|
net["id"], 0, 0)
|
||||||
|
self.assertIsNotNone(ipaddress[0]['id'])
|
||||||
|
expected = netaddr.IPAddress("0.0.0.2").ipv6().value
|
||||||
|
self.assertEqual(ipaddress[0]['address'], expected)
|
||||||
|
self.assertEqual(ipaddress[0]['version'], 4)
|
||||||
|
self.assertEqual(ipaddress[0]['used_by_tenant_id'], "fake")
|
||||||
|
|
||||||
|
def test_allocate_finds_ip_in_do_not_use_subnet_raises(self):
|
||||||
|
network = dict(name="public", tenant_id="fake")
|
||||||
|
ipnet = netaddr.IPNetwork("0.0.0.0/24")
|
||||||
|
next_ip = ipnet.ipv6().first + 3
|
||||||
|
subnet = dict(cidr="0.0.0.0/24", next_auto_assign_ip=next_ip,
|
||||||
|
ip_policy=None, tenant_id="fake", do_not_use=True)
|
||||||
|
|
||||||
|
addr = netaddr.IPAddress("0.0.0.2")
|
||||||
|
after_reuse_after = cfg.CONF.QUARK.ipam_reuse_after + 1
|
||||||
|
reusable_after = datetime.timedelta(seconds=after_reuse_after)
|
||||||
|
deallocated_at = timeutils.utcnow() - reusable_after
|
||||||
|
ip_address = dict(address=addr, version=4, _deallocated=True,
|
||||||
|
deallocated_at=deallocated_at)
|
||||||
|
|
||||||
|
with self._stubs(network, subnet, ip_address) as net:
|
||||||
|
with self.assertRaises(exceptions.IpAddressGenerationFailure):
|
||||||
|
self.ipam.allocate_ip_address(self.context, [], net["id"],
|
||||||
|
0, 0)
|
||||||
|
|
||||||
|
|
||||||
class QuarkIPAddressFindReallocatable(QuarkIpamBaseFunctionalTest):
|
class QuarkIPAddressFindReallocatable(QuarkIpamBaseFunctionalTest):
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def _stubs(self, network, subnet):
|
def _stubs(self, network, subnet):
|
||||||
|
|||||||
Reference in New Issue
Block a user