Only restrict gateway_ip change for router ports

The subnet update code was restricting gateway_ip changes if the
existing gateway IP belonged to a Neutron port. This was implemented
because changing the gateway will break all floating IP addresses if
the gateway is a Neutron router. However, this restriction makes it
possible to get a subnet stuck to an IP address that belongs to another
port (e.g. a compute port) so the user has to either delete the port
or change it's IP, both of which are disruptive.

This patch just changes the restriction so it only prevents gateway
IP changes if the current gateway IP belongs to a router. This
preserves the intent of the original change while allowing the subnet
to be updated off of IP addresses that belong to normal ports.

Change-Id: I4691505ef2fad6019e0d2fd80ff1b9e157662a29
Closes-bug: #1532004
This commit is contained in:
Kevin Benton 2016-01-07 14:28:24 -08:00 committed by Kevin Benton
parent df4966081a
commit 30dab936e6
2 changed files with 31 additions and 14 deletions

View File

@ -466,10 +466,12 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
# a subnet-update and a router-interface-add operation are
# executed concurrently
if cur_subnet and not ipv6_utils.is_ipv6_pd_enabled(s):
alloc_qry = context.session.query(models_v2.IPAllocation)
allocated = alloc_qry.filter_by(
ip_address=cur_subnet['gateway_ip'],
subnet_id=cur_subnet['id']).first()
ipal = models_v2.IPAllocation
alloc_qry = context.session.query(ipal)
alloc_qry = alloc_qry.join("port", "routerport")
allocated = alloc_qry.filter(
ipal.ip_address == cur_subnet['gateway_ip'],
ipal.subnet_id == cur_subnet['id']).first()
if allocated and allocated['port_id']:
raise n_exc.GatewayIpInUse(
ip_address=cur_subnet['gateway_ip'],

View File

@ -4177,22 +4177,37 @@ class TestSubnetsV2(NeutronDbPluginV2TestCase):
self.assertEqual(webob.exc.HTTPClientError.code,
res.status_int)
def test_update_subnet_gw_ip_in_use_returns_409(self):
def test_update_subnet_gw_ip_in_use_by_router_returns_409(self):
with self.network() as network:
with self.subnet(
network=network,
allocation_pools=[{'start': '10.0.0.100',
'end': '10.0.0.253'}]) as subnet:
subnet_data = subnet['subnet']
with self.subnet(network=network,
allocation_pools=[{'start': '10.0.0.2',
'end': '10.0.0.8'}]) as subnet:
s = subnet['subnet']
with self.port(
subnet=subnet,
fixed_ips=[{'subnet_id': subnet_data['id'],
'ip_address': subnet_data['gateway_ip']}]):
subnet=subnet, fixed_ips=[{'subnet_id': s['id'],
'ip_address': s['gateway_ip']}]
) as port:
# this protection only applies to router ports so we need
# to make this port belong to a router
ctx = context.get_admin_context()
with ctx.session.begin():
router = l3_db.Router()
ctx.session.add(router)
with ctx.session.begin():
rp = l3_db.RouterPort(router_id=router.id,
port_id=port['port']['id'])
ctx.session.add(rp)
data = {'subnet': {'gateway_ip': '10.0.0.99'}}
req = self.new_update_request('subnets', data,
subnet_data['id'])
s['id'])
res = req.get_response(self.api)
self.assertEqual(409, res.status_int)
# should work fine if it's not a router port
with ctx.session.begin():
ctx.session.delete(rp)
ctx.session.delete(router)
res = req.get_response(self.api)
self.assertEqual(res.status_int, 200)
def test_update_subnet_inconsistent_ipv4_gatewayv6(self):
with self.network() as network: