Merge "Network: enable instance deletion when dhcp release fails"
This commit is contained in:
commit
5becdc168a
@ -586,6 +586,10 @@ class NetworkDuplicated(Invalid):
|
|||||||
msg_fmt = _("Network %(network_id)s is duplicated.")
|
msg_fmt = _("Network %(network_id)s is duplicated.")
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkDhcpReleaseFailed(NovaException):
|
||||||
|
msg_fmt = _("Failed to release IP %(address)s with MAC %(mac_address)s")
|
||||||
|
|
||||||
|
|
||||||
class NetworkInUse(NovaException):
|
class NetworkInUse(NovaException):
|
||||||
msg_fmt = _("Network %(network_id)s is still in use.")
|
msg_fmt = _("Network %(network_id)s is still in use.")
|
||||||
|
|
||||||
|
@ -992,7 +992,12 @@ def get_dhcp_opts(context, network_ref, fixedips):
|
|||||||
|
|
||||||
|
|
||||||
def release_dhcp(dev, address, mac_address):
|
def release_dhcp(dev, address, mac_address):
|
||||||
utils.execute('dhcp_release', dev, address, mac_address, run_as_root=True)
|
try:
|
||||||
|
utils.execute('dhcp_release', dev, address, mac_address,
|
||||||
|
run_as_root=True)
|
||||||
|
except processutils.ProcessExecutionError:
|
||||||
|
raise exception.NetworkDhcpReleaseFailed(address=address,
|
||||||
|
mac_address=mac_address)
|
||||||
|
|
||||||
|
|
||||||
def update_dhcp(context, dev, network_ref):
|
def update_dhcp(context, dev, network_ref):
|
||||||
|
@ -39,7 +39,7 @@ from oslo import messaging
|
|||||||
from nova import conductor
|
from nova import conductor
|
||||||
from nova import context
|
from nova import context
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova.i18n import _
|
from nova.i18n import _, _LE
|
||||||
from nova import ipv6
|
from nova import ipv6
|
||||||
from nova import manager
|
from nova import manager
|
||||||
from nova.network import api as network_api
|
from nova.network import api as network_api
|
||||||
@ -1026,7 +1026,14 @@ class NetworkManager(manager.Manager):
|
|||||||
self._teardown_network_on_host(context, network)
|
self._teardown_network_on_host(context, network)
|
||||||
# NOTE(vish): This forces a packet so that the release_fixed_ip
|
# NOTE(vish): This forces a packet so that the release_fixed_ip
|
||||||
# callback will get called by nova-dhcpbridge.
|
# callback will get called by nova-dhcpbridge.
|
||||||
|
try:
|
||||||
self.driver.release_dhcp(dev, address, vif.address)
|
self.driver.release_dhcp(dev, address, vif.address)
|
||||||
|
except exception.NetworkDhcpReleaseFailed:
|
||||||
|
LOG.error(_LE("Error releasing DHCP for IP %(address)s "
|
||||||
|
"with MAC %(mac_address)s"),
|
||||||
|
{'address': address,
|
||||||
|
'mac_address': vif.address},
|
||||||
|
instance=instance)
|
||||||
|
|
||||||
# NOTE(yufang521247): This is probably a failed dhcp fixed ip.
|
# NOTE(yufang521247): This is probably a failed dhcp fixed ip.
|
||||||
# DHCPRELEASE packet sent to dnsmasq would not trigger
|
# DHCPRELEASE packet sent to dnsmasq would not trigger
|
||||||
|
@ -1668,6 +1668,50 @@ class VlanNetworkTestCase(test.TestCase):
|
|||||||
fixed_update.assert_called_once_with(context1, fix_addr.address,
|
fixed_update.assert_called_once_with(context1, fix_addr.address,
|
||||||
{'allocated': False})
|
{'allocated': False})
|
||||||
|
|
||||||
|
@mock.patch('nova.db.fixed_ip_get_by_address')
|
||||||
|
@mock.patch('nova.db.network_get')
|
||||||
|
@mock.patch('nova.db.fixed_ip_update')
|
||||||
|
def test_deallocate_fixed_with_dhcp_exception(self, fixed_update, net_get,
|
||||||
|
fixed_get):
|
||||||
|
net_get.return_value = dict(test_network.fake_network,
|
||||||
|
**networks[1])
|
||||||
|
|
||||||
|
def vif_get(_context, _vif_id):
|
||||||
|
return vifs[0]
|
||||||
|
|
||||||
|
with contextlib.nested(
|
||||||
|
mock.patch.object(db, 'virtual_interface_get', vif_get),
|
||||||
|
mock.patch.object(
|
||||||
|
utils, 'execute',
|
||||||
|
side_effect=processutils.ProcessExecutionError()),
|
||||||
|
) as (_vif_get, _execute):
|
||||||
|
context1 = context.RequestContext('user', 'project1')
|
||||||
|
|
||||||
|
instance = db.instance_create(context1,
|
||||||
|
{'project_id': 'project1'})
|
||||||
|
|
||||||
|
elevated = context1.elevated()
|
||||||
|
fix_addr = db.fixed_ip_associate_pool(elevated, 1,
|
||||||
|
instance['uuid'])
|
||||||
|
fixed_get.return_value = dict(test_fixed_ip.fake_fixed_ip,
|
||||||
|
address=fix_addr.address,
|
||||||
|
instance_uuid=instance.uuid,
|
||||||
|
allocated=True,
|
||||||
|
virtual_interface_id=3,
|
||||||
|
network=dict(
|
||||||
|
test_network.fake_network,
|
||||||
|
**networks[1]))
|
||||||
|
self.flags(force_dhcp_release=True)
|
||||||
|
self.network.deallocate_fixed_ip(context1, fix_addr.address,
|
||||||
|
'fake')
|
||||||
|
fixed_update.assert_called_once_with(context1, fix_addr.address,
|
||||||
|
{'allocated': False})
|
||||||
|
_execute.assert_called_once_with('dhcp_release',
|
||||||
|
networks[1]['bridge'],
|
||||||
|
fix_addr.address,
|
||||||
|
'DE:AD:BE:EF:00:00',
|
||||||
|
run_as_root=True)
|
||||||
|
|
||||||
def test_deallocate_fixed_deleted(self):
|
def test_deallocate_fixed_deleted(self):
|
||||||
# Verify doesn't deallocate deleted fixed_ip from deleted network.
|
# Verify doesn't deallocate deleted fixed_ip from deleted network.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user