Bug fixes for shared IPs
fixes #397, fixes #394, fixes #399, fixes #393, fixes #398
This commit is contained in:
@@ -318,6 +318,10 @@ def ip_address_find(context, lock_mode=False, **filters):
|
|||||||
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"])))
|
||||||
|
|
||||||
|
if filters.get("service"):
|
||||||
|
model_filters.append(models.IPAddress.ports.any(
|
||||||
|
models.Port.service == filters["service"]))
|
||||||
|
|
||||||
if filters.get("port_id"):
|
if filters.get("port_id"):
|
||||||
model_filters.append(models.IPAddress.ports.any(
|
model_filters.append(models.IPAddress.ports.any(
|
||||||
models.Port.id == filters['port_id']))
|
models.Port.id == filters['port_id']))
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ def create_ip_address(context, body):
|
|||||||
port = db_api.port_find(
|
port = db_api.port_find(
|
||||||
context, network_id=network_id, device_id=device_id,
|
context, network_id=network_id, device_id=device_id,
|
||||||
tenant_id=context.tenant_id, scope=db_api.ONE)
|
tenant_id=context.tenant_id, scope=db_api.ONE)
|
||||||
|
if port is not None:
|
||||||
ports.append(port)
|
ports.append(port)
|
||||||
elif port_ids:
|
elif port_ids:
|
||||||
for port_id in port_ids:
|
for port_id in port_ids:
|
||||||
@@ -127,6 +128,7 @@ def create_ip_address(context, body):
|
|||||||
port = db_api.port_find(context, id=port_id,
|
port = db_api.port_find(context, id=port_id,
|
||||||
tenant_id=context.tenant_id,
|
tenant_id=context.tenant_id,
|
||||||
scope=db_api.ONE)
|
scope=db_api.ONE)
|
||||||
|
if port is not None:
|
||||||
ports.append(port)
|
ports.append(port)
|
||||||
|
|
||||||
if not ports:
|
if not ports:
|
||||||
@@ -274,7 +276,7 @@ def get_ports_for_ip_address(context, ip_id, limit=None, sorts=None,
|
|||||||
if filters is None:
|
if filters is None:
|
||||||
filters = {}
|
filters = {}
|
||||||
|
|
||||||
filters['ip_address'] = ip_id
|
filters['ip_address_id'] = [ip_id]
|
||||||
|
|
||||||
ports = db_api.port_find(context, limit, sorts, marker,
|
ports = db_api.port_find(context, limit, sorts, marker,
|
||||||
fields=fields, join_security_groups=True,
|
fields=fields, join_security_groups=True,
|
||||||
@@ -298,7 +300,7 @@ def get_port_for_ip_address(context, ip_id, id, fields=None):
|
|||||||
if not addr:
|
if not addr:
|
||||||
raise quark_exceptions.IpAddressNotFound(addr_id=ip_id)
|
raise quark_exceptions.IpAddressNotFound(addr_id=ip_id)
|
||||||
|
|
||||||
filters = {'ip_address': ip_id}
|
filters = {'ip_address_id': [ip_id]}
|
||||||
results = db_api.port_find(context, id=id, fields=fields,
|
results = db_api.port_find(context, id=id, fields=fields,
|
||||||
scope=db_api.ONE, **filters)
|
scope=db_api.ONE, **filters)
|
||||||
|
|
||||||
|
|||||||
@@ -204,12 +204,16 @@ def _make_port_for_ip_dict(port, fields=None):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def _ip_is_fixed(port, ip):
|
||||||
|
at = ip.get('address_type')
|
||||||
|
return (not at or at == ip_types.FIXED or (at == ip_types.SHARED and
|
||||||
|
port.service != "none"))
|
||||||
|
|
||||||
|
|
||||||
def _make_port_dict(port, fields=None):
|
def _make_port_dict(port, fields=None):
|
||||||
res = _port_dict(port)
|
res = _port_dict(port)
|
||||||
res["fixed_ips"] = [_make_port_address_dict(ip, port, fields)
|
res["fixed_ips"] = [_make_port_address_dict(ip, port, fields)
|
||||||
for ip in port.ip_addresses
|
for ip in port.ip_addresses if _ip_is_fixed(port, ip)]
|
||||||
if (not ip.get("address_type") or
|
|
||||||
ip.get("address_type") == ip_types.FIXED)]
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
@@ -226,10 +230,8 @@ def _make_ports_list(query, fields=None):
|
|||||||
for port in query:
|
for port in query:
|
||||||
port_dict = _port_dict(port, fields)
|
port_dict = _port_dict(port, fields)
|
||||||
port_dict["fixed_ips"] = [_make_port_address_dict(ip, port, fields)
|
port_dict["fixed_ips"] = [_make_port_address_dict(ip, port, fields)
|
||||||
for ip in port.ip_addresses
|
for ip in port.ip_addresses if
|
||||||
if (not ip.get("address_type") or
|
_ip_is_fixed(port, ip)]
|
||||||
ip.get("address_type") == ip_types.FIXED)
|
|
||||||
]
|
|
||||||
ports.append(port_dict)
|
ports.append(port_dict)
|
||||||
return ports
|
return ports
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class MySqlBaseFunctionalTest(test_base.TestBase):
|
|||||||
'database')
|
'database')
|
||||||
cfg.CONF.set_override(
|
cfg.CONF.set_override(
|
||||||
'connection_debug',
|
'connection_debug',
|
||||||
'100',
|
'0',
|
||||||
'database')
|
'database')
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|||||||
223
quark/tests/functional/mysql/test_ip_addresses.py
Normal file
223
quark/tests/functional/mysql/test_ip_addresses.py
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
import mock
|
||||||
|
import netaddr
|
||||||
|
|
||||||
|
import contextlib
|
||||||
|
|
||||||
|
from oslo.config import cfg
|
||||||
|
from quark.db import ip_types
|
||||||
|
import quark.ipam
|
||||||
|
import quark.plugin
|
||||||
|
import quark.plugin_modules.ip_addresses as ip_api
|
||||||
|
import quark.plugin_modules.mac_address_ranges as macrng_api
|
||||||
|
import quark.plugin_modules.networks as network_api
|
||||||
|
import quark.plugin_modules.ports as port_api
|
||||||
|
import quark.plugin_modules.subnets as subnet_api
|
||||||
|
from quark.tests.functional.mysql.base import MySqlBaseFunctionalTest
|
||||||
|
|
||||||
|
|
||||||
|
class QuarkSharedIPs(MySqlBaseFunctionalTest):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(QuarkSharedIPs, self).__init__(*args, **kwargs)
|
||||||
|
self.cidr = "192.168.2.0/24"
|
||||||
|
self.ip_network = netaddr.IPNetwork(self.cidr)
|
||||||
|
network = dict(name="public", tenant_id="fake", network_plugin="BASE")
|
||||||
|
self.network = {"network": network}
|
||||||
|
subnet = dict(id=1, ip_version=4, next_auto_assign_ip=2,
|
||||||
|
cidr=self.cidr, first_ip=self.ip_network.first,
|
||||||
|
last_ip=self.ip_network.last, ip_policy=None,
|
||||||
|
tenant_id="fake")
|
||||||
|
self.subnet = {"subnet": subnet}
|
||||||
|
port1 = {'port': dict(device_id='a')}
|
||||||
|
port2 = {'port': dict(device_id='b')}
|
||||||
|
port3 = {'port': dict(device_id='c')}
|
||||||
|
port4 = {'port': dict(device_id='d')}
|
||||||
|
self.ports_info2 = [port1, port2]
|
||||||
|
self.ports_info4 = [port1, port2, port3, port4]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(QuarkSharedIPs, self).setUp()
|
||||||
|
self.old_show_port_service = cfg.CONF.QUARK.show_port_service
|
||||||
|
cfg.CONF.set_override('show_port_service', True, 'QUARK')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super(QuarkSharedIPs, self).tearDown()
|
||||||
|
cfg.CONF.set_override('show_port_service', self.old_show_port_service,
|
||||||
|
'QUARK')
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def _stubs(self, network_info, subnet_info, ports_info):
|
||||||
|
self.ipam = quark.ipam.QuarkIpamANY()
|
||||||
|
with contextlib.nested(
|
||||||
|
mock.patch("neutron.common.rpc.get_notifier"),
|
||||||
|
mock.patch("neutron.quota.QUOTAS.limit_check")):
|
||||||
|
net = network_api.create_network(self.context, network_info)
|
||||||
|
mac = {'mac_address_range': dict(cidr="AA:BB:CC")}
|
||||||
|
self.context.is_admin = True
|
||||||
|
macrng_api.create_mac_address_range(self.context, mac)
|
||||||
|
self.context.is_admin = False
|
||||||
|
subnet_info['subnet']['network_id'] = net['id']
|
||||||
|
sub = subnet_api.create_subnet(self.context, subnet_info)
|
||||||
|
ports = []
|
||||||
|
for port_info in ports_info:
|
||||||
|
port_info['port']['network_id'] = net['id']
|
||||||
|
ports.append(port_api.create_port(self.context, port_info))
|
||||||
|
yield net, sub, ports
|
||||||
|
|
||||||
|
def test_create_shared_ips_with_port_ids(self):
|
||||||
|
|
||||||
|
def _make_body(ip):
|
||||||
|
fix_ip = dict(ip_address=ip, subnet_id=sub['id'])
|
||||||
|
port_info = {"port": dict(fixed_ips=[fix_ip])}
|
||||||
|
return port_info
|
||||||
|
|
||||||
|
with self._stubs(self.network, self.subnet, self.ports_info2) as (
|
||||||
|
net, sub, ports):
|
||||||
|
for p in ports:
|
||||||
|
self.assertEqual('none', p.get('service'))
|
||||||
|
|
||||||
|
port_ids = [ports[0]['id'], ports[1]['id']]
|
||||||
|
shared_ip = {'ip_address': dict(port_ids=port_ids,
|
||||||
|
network_id=net['id'],
|
||||||
|
version=4)}
|
||||||
|
ip = ip_api.create_ip_address(self.context, shared_ip)
|
||||||
|
self.assertEqual(ip_types.SHARED, ip['address_type'])
|
||||||
|
|
||||||
|
ports_ip = ip_api.get_ports_for_ip_address(self.context, ip['id'])
|
||||||
|
self.assertEqual(2, len(ports_ip))
|
||||||
|
|
||||||
|
def test_shared_ip_in_fixed_ip_list(self):
|
||||||
|
|
||||||
|
def _make_body(service):
|
||||||
|
body = dict(service=service)
|
||||||
|
port_info = {"port": dict(body)}
|
||||||
|
return port_info
|
||||||
|
|
||||||
|
with self._stubs(self.network, self.subnet, self.ports_info2) as (
|
||||||
|
net, sub, ports):
|
||||||
|
for p in ports:
|
||||||
|
self.assertEqual('none', p.get('service'))
|
||||||
|
|
||||||
|
device_ids = [ports[0]['device_id'], ports[1]['device_id']]
|
||||||
|
shared_ip = {'ip_address': dict(device_ids=device_ids,
|
||||||
|
network_id=net['id'],
|
||||||
|
version=4)}
|
||||||
|
ip = ip_api.create_ip_address(self.context, shared_ip)
|
||||||
|
self.assertEqual(ip_types.SHARED, ip['address_type'])
|
||||||
|
|
||||||
|
ports_ip = ip_api.get_ports_for_ip_address(self.context, ip['id'])
|
||||||
|
self.assertEqual(2, len(ports_ip))
|
||||||
|
|
||||||
|
port = port_api.get_port(self.context, ports[0]['id'])
|
||||||
|
self.assertEqual(1, len(port['fixed_ips']))
|
||||||
|
|
||||||
|
port_ip_update = ip_api.update_port_for_ip_address
|
||||||
|
updated_port = port_ip_update(self.context, ip['id'],
|
||||||
|
ports[0]['id'], _make_body('derp'))
|
||||||
|
self.assertEqual('derp', updated_port.get('service'))
|
||||||
|
|
||||||
|
port = port_api.get_port(self.context, ports[0]['id'])
|
||||||
|
self.assertEqual(2, len(port['fixed_ips']))
|
||||||
|
|
||||||
|
def test_create_shared_ips_with_device_ids(self):
|
||||||
|
|
||||||
|
with self._stubs(self.network, self.subnet, self.ports_info2) as (
|
||||||
|
net, sub, ports):
|
||||||
|
for p in ports:
|
||||||
|
self.assertEqual('none', p.get('service'))
|
||||||
|
|
||||||
|
device_ids = [ports[0]['device_id'], ports[1]['device_id']]
|
||||||
|
shared_ip = {'ip_address': dict(device_ids=device_ids,
|
||||||
|
network_id=net['id'],
|
||||||
|
version=4)}
|
||||||
|
ip = ip_api.create_ip_address(self.context, shared_ip)
|
||||||
|
self.assertEqual(ip_types.SHARED, ip['address_type'])
|
||||||
|
|
||||||
|
ports_ip = ip_api.get_ports_for_ip_address(self.context, ip['id'])
|
||||||
|
self.assertEqual(2, len(ports_ip))
|
||||||
|
|
||||||
|
def test_filter_ip_by_device_and_service(self):
|
||||||
|
|
||||||
|
def _make_body(service):
|
||||||
|
body = dict(service=service)
|
||||||
|
port_info = {"port": dict(body)}
|
||||||
|
return port_info
|
||||||
|
|
||||||
|
with self._stubs(self.network, self.subnet, self.ports_info4) as (
|
||||||
|
net, sub, ports):
|
||||||
|
for p in ports:
|
||||||
|
self.assertEqual('none', p.get('service'))
|
||||||
|
|
||||||
|
port_ids1 = [ports[0]['id'], ports[1]['id']]
|
||||||
|
port_ids2 = [ports[2]['id'], ports[3]['id']]
|
||||||
|
|
||||||
|
shared_ip1 = {'ip_address': dict(port_ids=port_ids1,
|
||||||
|
network_id=net['id'],
|
||||||
|
version=4)}
|
||||||
|
ip1 = ip_api.create_ip_address(self.context, shared_ip1)
|
||||||
|
|
||||||
|
updated_port = port_api.update_port(self.context, ports[0]['id'],
|
||||||
|
_make_body('derp'))
|
||||||
|
self.assertEqual('derp', updated_port.get('service'))
|
||||||
|
for p in ports:
|
||||||
|
if p['id'] != ports[0]['id']:
|
||||||
|
self.assertEqual('none', p.get('service'))
|
||||||
|
|
||||||
|
shared_ip2 = {'ip_address': dict(port_ids=port_ids2,
|
||||||
|
network_id=net['id'],
|
||||||
|
version=4)}
|
||||||
|
ip2 = ip_api.create_ip_address(self.context, shared_ip2)
|
||||||
|
|
||||||
|
ports_ip = ip_api.get_ports_for_ip_address(self.context, ip1['id'])
|
||||||
|
self.assertEqual(2, len(ports_ip))
|
||||||
|
ports_ip = ip_api.get_ports_for_ip_address(self.context, ip2['id'])
|
||||||
|
self.assertEqual(2, len(ports_ip))
|
||||||
|
|
||||||
|
filters = dict(device_id='a', service='derp')
|
||||||
|
ips = ip_api.get_ip_addresses(self.context, **filters)
|
||||||
|
self.assertEqual(2, len(ips))
|
||||||
|
|
||||||
|
filters = dict(device_id='a', service='derp',
|
||||||
|
address_type=ip_types.FIXED)
|
||||||
|
ips = ip_api.get_ip_addresses(self.context, **filters)
|
||||||
|
self.assertEqual(1, len(ips))
|
||||||
|
|
||||||
|
filters = dict(device_id='a', service='derp',
|
||||||
|
address_type=ip_types.SHARED)
|
||||||
|
ips = ip_api.get_ip_addresses(self.context, **filters)
|
||||||
|
self.assertEqual(1, len(ips))
|
||||||
|
|
||||||
|
def test_get_ports_filter_with_ip_and_device(self):
|
||||||
|
|
||||||
|
with self._stubs(self.network, self.subnet, self.ports_info4) as (
|
||||||
|
net, sub, ports):
|
||||||
|
|
||||||
|
network = dict(name="xx", tenant_id="fake", network_plugin="BASE")
|
||||||
|
xx_network = {"network": network}
|
||||||
|
xx_net = network_api.create_network(self.context, xx_network)
|
||||||
|
subnet = dict(id=2, ip_version=4, next_auto_assign_ip=2,
|
||||||
|
cidr=self.cidr, first_ip=self.ip_network.first,
|
||||||
|
last_ip=self.ip_network.last, ip_policy=None,
|
||||||
|
tenant_id="fake")
|
||||||
|
xx_subnet = {"subnet": subnet}
|
||||||
|
xx_subnet['subnet']['network_id'] = xx_net['id']
|
||||||
|
subnet_api.create_subnet(self.context, xx_subnet)
|
||||||
|
|
||||||
|
port_info = {'port': dict(device_id='a')}
|
||||||
|
port_info['port']['network_id'] = xx_net['id']
|
||||||
|
port_api.create_port(self.context, port_info)
|
||||||
|
|
||||||
|
port_ids1 = [ports[0]['id'], ports[1]['id']]
|
||||||
|
|
||||||
|
shared_ip1 = {'ip_address': dict(port_ids=port_ids1,
|
||||||
|
network_id=net['id'],
|
||||||
|
version=4)}
|
||||||
|
ip1 = ip_api.create_ip_address(self.context, shared_ip1)
|
||||||
|
|
||||||
|
filters = dict(device_id='a')
|
||||||
|
ports = ip_api.get_ports_for_ip_address(self.context, ip1['id'],
|
||||||
|
filters=filters)
|
||||||
|
self.assertEqual(1, len(ports))
|
||||||
|
|
||||||
|
filters = dict(device_id='a')
|
||||||
|
ports = port_api.get_ports(self.context, filters=filters)
|
||||||
|
self.assertEqual(2, len(ports))
|
||||||
@@ -760,6 +760,11 @@ class TestQuarkGetIpAddressPort(test_quark_plugin.TestQuarkPlugin):
|
|||||||
self._alloc_stub(ip_model))
|
self._alloc_stub(ip_model))
|
||||||
|
|
||||||
res = self.plugin.get_ports_for_ip_address(self.context, 1)[0]
|
res = self.plugin.get_ports_for_ip_address(self.context, 1)[0]
|
||||||
|
mock_dbapi.port_find.assert_called_with(self.context, None, None, None,
|
||||||
|
join_security_groups=True,
|
||||||
|
fields=None,
|
||||||
|
ip_address_id=[1])
|
||||||
|
|
||||||
self.assertEqual(port["id"], res["id"])
|
self.assertEqual(port["id"], res["id"])
|
||||||
self.assertEqual(port["service"], res["service"])
|
self.assertEqual(port["service"], res["service"])
|
||||||
self.assertEqual(port["device_id"], res["device_id"])
|
self.assertEqual(port["device_id"], res["device_id"])
|
||||||
@@ -773,18 +778,32 @@ class TestQuarkGetIpAddressPort(test_quark_plugin.TestQuarkPlugin):
|
|||||||
tenant_id=self.context.tenant_id, device_id=2,
|
tenant_id=self.context.tenant_id, device_id=2,
|
||||||
bridge="xenbr0", device_owner='network:dhcp',
|
bridge="xenbr0", device_owner='network:dhcp',
|
||||||
service='none', id=100)
|
service='none', id=100)
|
||||||
|
port2 = dict(mac_address="AA:BB:CC:DD:EE:FF", network_id=1,
|
||||||
|
tenant_id=self.context.tenant_id, device_id=2,
|
||||||
|
bridge="xenbr0", device_owner='network:dhcp',
|
||||||
|
service='none', id=100)
|
||||||
ip = dict(id=1, address=3232235876, address_readable="192.168.1.100",
|
ip = dict(id=1, address=3232235876, address_readable="192.168.1.100",
|
||||||
subnet_id=1, network_id=2, version=4)
|
subnet_id=1, network_id=2, version=4)
|
||||||
port_model = models.Port()
|
port_model = models.Port()
|
||||||
port_model.update(port)
|
port_model.update(port)
|
||||||
|
port_model2 = models.Port()
|
||||||
|
port_model2.update(port2)
|
||||||
ip_model = models.IPAddress()
|
ip_model = models.IPAddress()
|
||||||
ip_model.update(ip)
|
ip_model.update(ip)
|
||||||
|
|
||||||
mock_dbapi.port_find.return_value = port_model
|
mock_dbapi.port_find.return_value = port_model
|
||||||
mock_ipam.allocate_ip_address.side_effect = (
|
mock_ipam.allocate_ip_address.side_effect = (
|
||||||
self._alloc_stub(ip_model))
|
self._alloc_stub(ip_model))
|
||||||
|
mock_dbapi.ip_address_find.return_value = ip_model
|
||||||
|
|
||||||
res = self.plugin.get_port_for_ip_address(self.context, 1, 100)
|
res = self.plugin.get_port_for_ip_address(self.context, 1, 100)
|
||||||
|
|
||||||
|
mock_dbapi.ip_address_find.assert_called_with(self.context,
|
||||||
|
scope=mock_dbapi.ONE,
|
||||||
|
id=1)
|
||||||
|
mock_dbapi.port_find.assert_called_with(self.context, fields=None,
|
||||||
|
id=100, ip_address_id=[1],
|
||||||
|
scope=mock_dbapi.ONE)
|
||||||
self.assertEqual(port["id"], res["id"])
|
self.assertEqual(port["id"], res["id"])
|
||||||
self.assertEqual(port["service"], res["service"])
|
self.assertEqual(port["service"], res["service"])
|
||||||
self.assertEqual(port["device_id"], res["device_id"])
|
self.assertEqual(port["device_id"], res["device_id"])
|
||||||
|
|||||||
Reference in New Issue
Block a user