NSX|V3: Support specific IP allocations in IPAM
The new NSX-V3 version supports allocation of specific IPs. This patch adds the relevant error handling, and all the relevant tests. Depends-on: Ic717023a41657e2de9200e38a3354ca76ee134f5 Change-Id: I822127a342f0ee63cf72ceededd1efa6e2753b94
This commit is contained in:
parent
fb54cc2839
commit
27ab7111df
@ -163,16 +163,20 @@ class Nsxv3IpamSubnet(common.NsxAbstractIpamSubnet):
|
|||||||
'ip': ip_address,
|
'ip': ip_address,
|
||||||
'id': self._subnet_id,
|
'id': self._subnet_id,
|
||||||
'code': e.error_code})
|
'code': e.error_code})
|
||||||
# Currently the backend does not support allocation of specific IPs
|
|
||||||
# When this support is added we should handle allocation errors.
|
|
||||||
if e.error_code == error.ERR_CODE_IPAM_POOL_EXHAUSTED:
|
if e.error_code == error.ERR_CODE_IPAM_POOL_EXHAUSTED:
|
||||||
# No more IP addresses available on the pool
|
# No more IP addresses available on the pool
|
||||||
raise ipam_exc.IpAddressGenerationFailure(
|
raise ipam_exc.IpAddressGenerationFailure(
|
||||||
subnet_id=self._subnet_id)
|
subnet_id=self._subnet_id)
|
||||||
if e.error_code == error.ERR_CODE_IPAM_SPECIFIC_IP:
|
if e.error_code == error.ERR_CODE_IPAM_SPECIFIC_IP:
|
||||||
|
# The NSX backend does not support allocation of specific IPs
|
||||||
|
# prior to version 2.0.
|
||||||
msg = (_("NSX-V3 IPAM driver does not support allocation of a "
|
msg = (_("NSX-V3 IPAM driver does not support allocation of a "
|
||||||
"specific ip %s for port") % ip_address)
|
"specific ip %s for port") % ip_address)
|
||||||
raise NotImplementedError(msg)
|
raise NotImplementedError(msg)
|
||||||
|
if e.error_code == error.ERR_CODE_IPAM_IP_ALLOCATED:
|
||||||
|
# This IP is already in use
|
||||||
|
raise ipam_exc.IpAddressAlreadyAllocated(
|
||||||
|
ip=ip_address, subnet_id=self._subnet_id)
|
||||||
if e.error_code == error.ERR_CODE_OBJECT_NOT_FOUND:
|
if e.error_code == error.ERR_CODE_OBJECT_NOT_FOUND:
|
||||||
msg = (_("NSX-V3 IPAM failed to allocate: pool %s was not "
|
msg = (_("NSX-V3 IPAM failed to allocate: pool %s was not "
|
||||||
"found") % self._nsx_pool_id)
|
"found") % self._nsx_pool_id)
|
||||||
@ -190,15 +194,21 @@ class Nsxv3IpamSubnet(common.NsxAbstractIpamSubnet):
|
|||||||
raise ipam_exc.IPAllocationFailed()
|
raise ipam_exc.IPAllocationFailed()
|
||||||
return ip_address
|
return ip_address
|
||||||
|
|
||||||
def backend_deallocate(self, address):
|
def backend_deallocate(self, ip_address):
|
||||||
|
# If this is the subnet gateway IP - no need to allocate it
|
||||||
|
subnet = self.get_details()
|
||||||
|
if str(subnet.gateway_ip) == ip_address:
|
||||||
|
LOG.info("Skip deallocation of gateway-ip for pool %s",
|
||||||
|
self._nsx_pool_id)
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
self.nsxlib_ipam.release(self._nsx_pool_id, ip_addr=address)
|
self.nsxlib_ipam.release(self._nsx_pool_id, ip_address)
|
||||||
except nsx_lib_exc.ManagerError as e:
|
except nsx_lib_exc.ManagerError as e:
|
||||||
# fail silently
|
# fail silently
|
||||||
LOG.error("NSX IPAM failed to free ip %(ip)s of subnet "
|
LOG.error("NSX IPAM failed to free ip %(ip)s of subnet "
|
||||||
"%(id)s: %(e)s; code %(code)s",
|
"%(id)s: %(e)s; code %(code)s",
|
||||||
{'e': e,
|
{'e': e,
|
||||||
'ip': address,
|
'ip': ip_address,
|
||||||
'id': self._subnet_id,
|
'id': self._subnet_id,
|
||||||
'code': e.error_code})
|
'code': e.error_code})
|
||||||
|
|
||||||
@ -225,7 +235,6 @@ class Nsxv3IpamSubnet(common.NsxAbstractIpamSubnet):
|
|||||||
for ip_range in subnet.get('allocation_ranges', []):
|
for ip_range in subnet.get('allocation_ranges', []):
|
||||||
pools.append(netaddr.IPRange(ip_range.get('start'),
|
pools.append(netaddr.IPRange(ip_range.get('start'),
|
||||||
ip_range.get('end')))
|
ip_range.get('end')))
|
||||||
|
|
||||||
return ipam_req.SpecificSubnetRequest(
|
return ipam_req.SpecificSubnetRequest(
|
||||||
self._tenant_id, self._subnet_id,
|
self._tenant_id, self._subnet_id,
|
||||||
cidr, gateway_ip=gateway_ip, allocation_pools=pools)
|
cidr, gateway_ip=gateway_ip, allocation_pools=pools)
|
||||||
|
@ -63,14 +63,18 @@ class MockIPPools(object):
|
|||||||
return self.nsx_pools[pool_id]['pool']
|
return self.nsx_pools[pool_id]['pool']
|
||||||
|
|
||||||
def _allocate_ip(*args, **kwargs):
|
def _allocate_ip(*args, **kwargs):
|
||||||
#TODO(asarfaty): add support for specific ip allocation
|
nsx_pool = self.nsx_pools[args[0]]
|
||||||
if kwargs.get('ip_addr'):
|
if kwargs.get('ip_addr'):
|
||||||
|
ip_addr = netaddr.IPAddress(kwargs['ip_addr'])
|
||||||
|
# verify that this ip was not yet allocated
|
||||||
|
if ip_addr in nsx_pool['allocated']:
|
||||||
raise nsx_lib_exc.ManagerError(
|
raise nsx_lib_exc.ManagerError(
|
||||||
manager='dummy', operation='allocate',
|
manager='dummy', operation='allocate',
|
||||||
details='allocating specific IP is not supported',
|
details='IP already allocated',
|
||||||
error_code=error.ERR_CODE_IPAM_SPECIFIC_IP)
|
error_code=error.ERR_CODE_IPAM_IP_ALLOCATED)
|
||||||
|
# skip ip validation for this mock.
|
||||||
nsx_pool = self.nsx_pools[args[0]]
|
nsx_pool['allocated'].append(ip_addr)
|
||||||
|
return {'allocation_id': str(ip_addr)}
|
||||||
# get an unused ip from the pool
|
# get an unused ip from the pool
|
||||||
ranges = nsx_pool['pool']['subnets'][0]['allocation_ranges']
|
ranges = nsx_pool['pool']['subnets'][0]['allocation_ranges']
|
||||||
for ip_range in ranges:
|
for ip_range in ranges:
|
||||||
@ -85,6 +89,11 @@ class MockIPPools(object):
|
|||||||
details='All IPs in the pool are allocated',
|
details='All IPs in the pool are allocated',
|
||||||
error_code=error.ERR_CODE_IPAM_POOL_EXHAUSTED)
|
error_code=error.ERR_CODE_IPAM_POOL_EXHAUSTED)
|
||||||
|
|
||||||
|
def _release_ip(*args, **kwargs):
|
||||||
|
nsx_pool = self.nsx_pools[args[0]]
|
||||||
|
ip_addr = netaddr.IPAddress(args[1])
|
||||||
|
nsx_pool['allocated'].remove(ip_addr)
|
||||||
|
|
||||||
mock.patch(
|
mock.patch(
|
||||||
"vmware_nsxlib.v3.resources.IpPool.get",
|
"vmware_nsxlib.v3.resources.IpPool.get",
|
||||||
side_effect=_get_pool).start()
|
side_effect=_get_pool).start()
|
||||||
@ -101,7 +110,8 @@ class MockIPPools(object):
|
|||||||
"vmware_nsxlib.v3.resources.IpPool.allocate",
|
"vmware_nsxlib.v3.resources.IpPool.allocate",
|
||||||
side_effect=_allocate_ip).start()
|
side_effect=_allocate_ip).start()
|
||||||
mock.patch(
|
mock.patch(
|
||||||
"vmware_nsxlib.v3.resources.IpPool.release").start()
|
"vmware_nsxlib.v3.resources.IpPool.release",
|
||||||
|
side_effect=_release_ip).start()
|
||||||
|
|
||||||
|
|
||||||
class TestNsxv3IpamSubnets(test_plugin.TestSubnetsV2, MockIPPools):
|
class TestNsxv3IpamSubnets(test_plugin.TestSubnetsV2, MockIPPools):
|
||||||
@ -113,35 +123,11 @@ class TestNsxv3IpamSubnets(test_plugin.TestSubnetsV2, MockIPPools):
|
|||||||
super(TestNsxv3IpamSubnets, self).setUp()
|
super(TestNsxv3IpamSubnets, self).setUp()
|
||||||
self.patch_nsxlib_ipam()
|
self.patch_nsxlib_ipam()
|
||||||
|
|
||||||
def test_update_subnet_gw_ip_in_use_by_router_returns_409(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_subnet_with_allocation_range(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_delete_subnet_ipv6_slaac_port_exists(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_create_subnet_ipv6_slaac_with_port_on_network(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_create_subnet_ipv6_slaac_with_dhcp_port_on_network(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_create_subnet_dhcpv6_stateless_with_port_on_network(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_create_subnet_ipv6_slaac_with_port_not_found(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_create_subnet_ipv6_slaac_with_db_reference_error(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_subnet_update_ipv4_and_ipv6_pd_slaac_subnets(self):
|
def test_subnet_update_ipv4_and_ipv6_pd_slaac_subnets(self):
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
self.skipTest('Update ipam subnet is not supported')
|
||||||
|
|
||||||
def test_subnet_update_ipv4_and_ipv6_pd_v6stateless_subnets(self):
|
def test_subnet_update_ipv4_and_ipv6_pd_v6stateless_subnets(self):
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
self.skipTest('Update ipam subnet is not supported')
|
||||||
|
|
||||||
|
|
||||||
class TestNsxv3IpamPorts(test_plugin.TestPortsV2, MockIPPools):
|
class TestNsxv3IpamPorts(test_plugin.TestPortsV2, MockIPPools):
|
||||||
@ -153,66 +139,6 @@ class TestNsxv3IpamPorts(test_plugin.TestPortsV2, MockIPPools):
|
|||||||
super(TestNsxv3IpamPorts, self).setUp()
|
super(TestNsxv3IpamPorts, self).setUp()
|
||||||
self.patch_nsxlib_ipam()
|
self.patch_nsxlib_ipam()
|
||||||
|
|
||||||
def test_update_port_mac_v6_slaac(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_create_port_with_multiple_ipv4_and_ipv6_subnets(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_create_port_with_ipv6_slaac_subnet_in_fixed_ips(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_update_port_with_new_ipv6_slaac_subnet_in_fixed_ips(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_create_port_with_ipv6_pd_subnet_in_fixed_ips(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_create_port_anticipating_allocation(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_update_port_with_ipv6_slaac_subnet_in_fixed_ips(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_update_port_mac_ip(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_update_port_update_ips(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_update_port_excluding_ipv6_slaac_subnet_from_fixed_ips(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_update_port_update_ip(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_requested_subnet_id_v6_slaac(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_update_port_invalid_fixed_ip_address_v6_slaac(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_update_dhcp_port_with_exceeding_fixed_ips(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_requested_subnet_id_v4_and_v6_slaac(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_requested_ips_only(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_ip_allocation_for_ipv6_subnet_slaac_address_mode(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_ip_allocation_for_ipv6_2_subnet_slaac_mode(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_delete_port_with_ipv6_slaac_address(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_requested_duplicate_ip(self):
|
|
||||||
self.skipTest('Allocating a specific IP is not supported')
|
|
||||||
|
|
||||||
def test_create_port_invalid_fixed_ip_address_v6_pd_slaac(self):
|
def test_create_port_invalid_fixed_ip_address_v6_pd_slaac(self):
|
||||||
self.skipTest('Update ipam subnet is not supported')
|
self.skipTest('Update ipam subnet is not supported')
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user