Merge "Add existed network failed if the gateway already created"
This commit is contained in:
@@ -34,6 +34,8 @@ NEUTRON_ID_LH_OPTION = 'kuryr.net.uuid.lh'
|
|||||||
NEUTRON_ID_UH_OPTION = 'kuryr.net.uuid.uh'
|
NEUTRON_ID_UH_OPTION = 'kuryr.net.uuid.uh'
|
||||||
NET_NAME_PREFIX = 'kuryr-net-'
|
NET_NAME_PREFIX = 'kuryr-net-'
|
||||||
|
|
||||||
|
REQUEST_ADDRESS_TYPE = 'RequestAddressType'
|
||||||
|
NETWORK_GATEWAY_OPTIONS = 'com.docker.network.gateway'
|
||||||
NETWORK_GENERIC_OPTIONS = 'com.docker.network.generic'
|
NETWORK_GENERIC_OPTIONS = 'com.docker.network.generic'
|
||||||
NEUTRON_UUID_OPTION = 'neutron.net.uuid'
|
NEUTRON_UUID_OPTION = 'neutron.net.uuid'
|
||||||
NEUTRON_NAME_OPTION = 'neutron.net.name'
|
NEUTRON_NAME_OPTION = 'neutron.net.name'
|
||||||
|
@@ -39,6 +39,14 @@ class DuplicatedResourceException(KuryrException):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class GatewayConflictFailure(KuryrException):
|
||||||
|
"""Exception represents gateway ip is conflict.
|
||||||
|
|
||||||
|
This exception is thrown when request gateway ip is conflict with the
|
||||||
|
gateway ip in existed network.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class MandatoryApiMissing(KuryrException):
|
class MandatoryApiMissing(KuryrException):
|
||||||
"""Exception represents that mandatory api is not found.
|
"""Exception represents that mandatory api is not found.
|
||||||
|
|
||||||
|
@@ -1085,6 +1085,7 @@ def ipam_request_address():
|
|||||||
jsonschema.validate(json_data, schemata.REQUEST_ADDRESS_SCHEMA)
|
jsonschema.validate(json_data, schemata.REQUEST_ADDRESS_SCHEMA)
|
||||||
pool_id = json_data['PoolID']
|
pool_id = json_data['PoolID']
|
||||||
req_address = json_data['Address']
|
req_address = json_data['Address']
|
||||||
|
is_gateway = False
|
||||||
allocated_address = ''
|
allocated_address = ''
|
||||||
subnet_cidr = ''
|
subnet_cidr = ''
|
||||||
pool_prefix_len = ''
|
pool_prefix_len = ''
|
||||||
@@ -1108,31 +1109,48 @@ def ipam_request_address():
|
|||||||
.format(pool_id))
|
.format(pool_id))
|
||||||
# check if any subnet with matching cidr is present
|
# check if any subnet with matching cidr is present
|
||||||
subnets = _get_subnets_by_attrs(cidr=subnet_cidr)
|
subnets = _get_subnets_by_attrs(cidr=subnet_cidr)
|
||||||
|
# Check if the port is gateway
|
||||||
|
options = json_data.get('Options')
|
||||||
|
if options:
|
||||||
|
request_address_type = options.get(const.REQUEST_ADDRESS_TYPE)
|
||||||
|
if request_address_type == const.NETWORK_GATEWAY_OPTIONS:
|
||||||
|
is_gateway = True
|
||||||
if subnets:
|
if subnets:
|
||||||
subnet = subnets[0]
|
subnet = subnets[0]
|
||||||
# allocating address for container port
|
if is_gateway:
|
||||||
neutron_network_id = subnet['network_id']
|
# check if request gateway ip same with existed gateway ip
|
||||||
try:
|
existed_gateway_ip = subnet.get('gateway_ip', '')
|
||||||
port = {
|
if req_address == existed_gateway_ip:
|
||||||
'name': 'kuryr-unbound-port',
|
allocated_address = '/'.join([req_address, pool_prefix_len])
|
||||||
'admin_state_up': True,
|
else:
|
||||||
'network_id': neutron_network_id,
|
raise exceptions.GatewayConflictFailure(
|
||||||
'binding:host_id': utils.get_hostname(),
|
"Requested gateway {0} does not match with "
|
||||||
}
|
"gateway {1} in existed "
|
||||||
fixed_ips = port['fixed_ips'] = []
|
"network.".format(req_address, existed_gateway_ip))
|
||||||
fixed_ip = {'subnet_id': subnet['id']}
|
else:
|
||||||
if req_address:
|
# allocating address for container port
|
||||||
fixed_ip['ip_address'] = req_address
|
neutron_network_id = subnet['network_id']
|
||||||
fixed_ips.append(fixed_ip)
|
try:
|
||||||
created_port_resp = app.neutron.create_port({'port': port})
|
port = {
|
||||||
created_port = created_port_resp['port']
|
'name': 'kuryr-unbound-port',
|
||||||
allocated_address = created_port['fixed_ips'][0]['ip_address']
|
'admin_state_up': True,
|
||||||
allocated_address = '/'.join(
|
'network_id': neutron_network_id,
|
||||||
[allocated_address, str(cidr.prefixlen)])
|
'binding:host_id': utils.get_hostname(),
|
||||||
except n_exceptions.NeutronClientException as ex:
|
}
|
||||||
app.logger.error(_LE("Error happened during ip allocation on "
|
fixed_ips = port['fixed_ips'] = []
|
||||||
"Neutron side: %s"), ex)
|
fixed_ip = {'subnet_id': subnet['id']}
|
||||||
raise
|
if req_address:
|
||||||
|
fixed_ip['ip_address'] = req_address
|
||||||
|
fixed_ips.append(fixed_ip)
|
||||||
|
created_port_resp = app.neutron.create_port({'port': port})
|
||||||
|
created_port = created_port_resp['port']
|
||||||
|
allocated_address = created_port['fixed_ips'][0]['ip_address']
|
||||||
|
allocated_address = '/'.join(
|
||||||
|
[allocated_address, str(cidr.prefixlen)])
|
||||||
|
except n_exceptions.NeutronClientException as ex:
|
||||||
|
app.logger.error(_LE("Error happened during ip allocation on "
|
||||||
|
"Neutron side: %s"), ex)
|
||||||
|
raise
|
||||||
else:
|
else:
|
||||||
# Auxiliary address or gw_address is received at network creation time.
|
# Auxiliary address or gw_address is received at network creation time.
|
||||||
# This address cannot be reserved with neutron at this time as subnet
|
# This address cannot be reserved with neutron at this time as subnet
|
||||||
|
@@ -15,6 +15,7 @@ from oslo_serialization import jsonutils
|
|||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from kuryr.common import config
|
from kuryr.common import config
|
||||||
|
from kuryr.common import constants as const
|
||||||
from kuryr.controllers import app
|
from kuryr.controllers import app
|
||||||
from kuryr.tests.unit import base
|
from kuryr.tests.unit import base
|
||||||
from kuryr import utils
|
from kuryr import utils
|
||||||
@@ -227,6 +228,106 @@ class TestKuryrIpam(base.TestKuryrBase):
|
|||||||
decoded_json = jsonutils.loads(response.data)
|
decoded_json = jsonutils.loads(response.data)
|
||||||
self.assertEqual('10.0.0.5/16', decoded_json['Address'])
|
self.assertEqual('10.0.0.5/16', decoded_json['Address'])
|
||||||
|
|
||||||
|
def test_ipam_driver_request_address_for_same_gateway(self):
|
||||||
|
# faking list_subnetpools
|
||||||
|
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
||||||
|
fake_kuryr_subnetpool_id = str(uuid.uuid4())
|
||||||
|
fake_name = utils.get_neutron_subnetpool_name(FAKE_IP4_CIDR)
|
||||||
|
kuryr_subnetpools = self._get_fake_v4_subnetpools(
|
||||||
|
fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR],
|
||||||
|
name=fake_name)
|
||||||
|
app.neutron.list_subnetpools(id=fake_kuryr_subnetpool_id).AndReturn(
|
||||||
|
kuryr_subnetpools)
|
||||||
|
|
||||||
|
# faking list_subnets
|
||||||
|
docker_endpoint_id = utils.get_hash()
|
||||||
|
neutron_network_id = str(uuid.uuid4())
|
||||||
|
subnet_v4_id = str(uuid.uuid4())
|
||||||
|
fake_v4_subnet = self._get_fake_v4_subnet(
|
||||||
|
neutron_network_id, docker_endpoint_id, subnet_v4_id,
|
||||||
|
subnetpool_id=fake_kuryr_subnetpool_id,
|
||||||
|
cidr=FAKE_IP4_CIDR)
|
||||||
|
fake_v4_subnet['subnet'].update(gateway_ip='10.0.0.1')
|
||||||
|
fake_subnet_response = {
|
||||||
|
'subnets': [
|
||||||
|
fake_v4_subnet['subnet']
|
||||||
|
]
|
||||||
|
}
|
||||||
|
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
||||||
|
app.neutron.list_subnets(cidr=FAKE_IP4_CIDR).AndReturn(
|
||||||
|
fake_subnet_response)
|
||||||
|
|
||||||
|
# Apply mocks
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
# Testing container ip allocation
|
||||||
|
fake_request = {
|
||||||
|
'PoolID': fake_kuryr_subnetpool_id,
|
||||||
|
'Address': '10.0.0.1',
|
||||||
|
'Options': {
|
||||||
|
const.REQUEST_ADDRESS_TYPE: const.NETWORK_GATEWAY_OPTIONS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response = self.app.post('/IpamDriver.RequestAddress',
|
||||||
|
content_type='application/json',
|
||||||
|
data=jsonutils.dumps(fake_request))
|
||||||
|
|
||||||
|
self.assertEqual(200, response.status_code)
|
||||||
|
decoded_json = jsonutils.loads(response.data)
|
||||||
|
self.assertEqual('10.0.0.1/16', decoded_json['Address'])
|
||||||
|
|
||||||
|
def test_ipam_driver_request_address_for_different_gateway(self):
|
||||||
|
# faking list_subnetpools
|
||||||
|
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
||||||
|
fake_kuryr_subnetpool_id = str(uuid.uuid4())
|
||||||
|
fake_name = utils.get_neutron_subnetpool_name(FAKE_IP4_CIDR)
|
||||||
|
kuryr_subnetpools = self._get_fake_v4_subnetpools(
|
||||||
|
fake_kuryr_subnetpool_id, prefixes=[FAKE_IP4_CIDR],
|
||||||
|
name=fake_name)
|
||||||
|
app.neutron.list_subnetpools(id=fake_kuryr_subnetpool_id).AndReturn(
|
||||||
|
kuryr_subnetpools)
|
||||||
|
|
||||||
|
# faking list_subnets
|
||||||
|
docker_endpoint_id = utils.get_hash()
|
||||||
|
neutron_network_id = str(uuid.uuid4())
|
||||||
|
subnet_v4_id = str(uuid.uuid4())
|
||||||
|
fake_v4_subnet = self._get_fake_v4_subnet(
|
||||||
|
neutron_network_id, docker_endpoint_id, subnet_v4_id,
|
||||||
|
subnetpool_id=fake_kuryr_subnetpool_id,
|
||||||
|
cidr=FAKE_IP4_CIDR)
|
||||||
|
fake_v4_subnet['subnet'].update(gateway_ip='10.0.0.1')
|
||||||
|
fake_subnet_response = {
|
||||||
|
'subnets': [
|
||||||
|
fake_v4_subnet['subnet']
|
||||||
|
]
|
||||||
|
}
|
||||||
|
self.mox.StubOutWithMock(app.neutron, 'list_subnets')
|
||||||
|
app.neutron.list_subnets(cidr=FAKE_IP4_CIDR).AndReturn(
|
||||||
|
fake_subnet_response)
|
||||||
|
|
||||||
|
# Apply mocks
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
# Testing container ip allocation
|
||||||
|
fake_request = {
|
||||||
|
'PoolID': fake_kuryr_subnetpool_id,
|
||||||
|
'Address': '10.0.0.5', # Different with existed gw ip
|
||||||
|
'Options': {
|
||||||
|
const.REQUEST_ADDRESS_TYPE: const.NETWORK_GATEWAY_OPTIONS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response = self.app.post('/IpamDriver.RequestAddress',
|
||||||
|
content_type='application/json',
|
||||||
|
data=jsonutils.dumps(fake_request))
|
||||||
|
|
||||||
|
self.assertEqual(500, response.status_code)
|
||||||
|
decoded_json = jsonutils.loads(response.data)
|
||||||
|
self.assertIn('Err', decoded_json)
|
||||||
|
err_message = ("Requested gateway {0} does not match with "
|
||||||
|
"gateway {1} in existed network.").format(
|
||||||
|
'10.0.0.5', '10.0.0.1')
|
||||||
|
self.assertEqual({'Err': err_message}, decoded_json)
|
||||||
|
|
||||||
def test_ipam_driver_release_address(self):
|
def test_ipam_driver_release_address(self):
|
||||||
# faking list_subnetpools
|
# faking list_subnetpools
|
||||||
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
self.mox.StubOutWithMock(app.neutron, 'list_subnetpools')
|
||||||
|
Reference in New Issue
Block a user