dhcp: make device manager to clean only not used devices

This change makes device manager action to clean device a bit smarter
by comparing port registered for a given network with device in live.

Partial-Bug: #1956435
Partial-Bug: #1764738
Signed-off-by: Sahid Orentino Ferdjaoui <sahid.ferdjaoui@industrialdiscipline.com>
Change-Id: I0b6f9b59b94cf05996e4217b5d232b69ad775502
This commit is contained in:
Sahid Orentino Ferdjaoui 2022-04-29 12:02:45 +02:00
parent 599c81767e
commit 1d8e3b79db
2 changed files with 30 additions and 12 deletions

View File

@ -1677,19 +1677,23 @@ class DeviceManager(object):
network.ports.append(port)
def _cleanup_stale_devices(self, network, dhcp_port):
"""Unplug any devices found in the namespace except for dhcp_port."""
"""Unplug unrelated or stale devices found in the namespace."""
LOG.debug("Cleaning stale devices for network %s", network.id)
skip_dev_name = (self.driver.get_device_name(dhcp_port)
if dhcp_port else None)
ns_ip = ip_lib.IPWrapper(namespace=network.namespace)
if not ns_ip.netns.exists(network.namespace):
return
for d in ns_ip.get_devices():
# delete all devices except current active DHCP port device
if d.name != skip_dev_name:
LOG.debug("Found stale device %s, deleting", d.name)
db_ports = {self.get_interface_name(network, port)
for port in network.ports}
hw_ports = {d.name for d in ns_ip.get_devices()}
for dev_name in hw_ports - db_ports:
if dev_name != skip_dev_name:
LOG.debug("Found stale device %s, deleting", dev_name)
try:
self.unplug(d.name, network)
self.unplug(dev_name, network)
except Exception:
LOG.exception("Exception during stale "
"dhcp device cleanup")

View File

@ -49,11 +49,17 @@ class TestDhcp(functional_base.BaseSudoTestCase):
plugin = mock.MagicMock()
dev_mgr = dhcp.DeviceManager(self.conf, plugin)
spool_id = uuidutils.generate_uuid()
dhcp_port4 = tests_base.AttributeDict({
'id': 'foo_id4',
'mac_address': '10:22:33:44:55:70',
'fixed_ips': [tests_base.AttributeDict(
{'subnet_id': 'subnet_foo_id4', 'ip_address': '10.0.0.4'})]
})
network = {
'id': 'foo_id',
'project_id': 'foo_project',
'namespace': 'qdhcp-foo_id',
'ports': [],
'ports': [dhcp_port4],
'subnets': [tests_base.AttributeDict({'id': 'subnet_foo_id',
'enable_dhcp': True,
'ipv6_address_mode': None,
@ -64,7 +70,7 @@ class TestDhcp(functional_base.BaseSudoTestCase):
constants.IP_VERSION_4,
'gateway_ip': '10.0.0.1'})]}
dhcp_port = {
'id': 'foo_port_id',
'id': 'foo_id',
'mac_address': '10:22:33:44:55:67',
'fixed_ips': [tests_base.AttributeDict(
{'subnet_id': 'subnet_foo_id', 'ip_address': '10.0.0.1'})]
@ -81,17 +87,25 @@ class TestDhcp(functional_base.BaseSudoTestCase):
"tapfoo_id3",
"10:22:33:44:55:69",
namespace="qdhcp-foo_id")
dev_mgr.driver.plug("foo_id",
"foo_id4",
"tapfoo_id4",
"10:22:33:44:55:70",
namespace="qdhcp-foo_id")
ipw = ip_lib.IPWrapper(namespace="qdhcp-foo_id")
devices = ipw.get_devices()
self.addCleanup(ipw.netns.delete, 'qdhcp-foo_id')
self.assertEqual(sorted(["tapfoo_id2", "tapfoo_id3"]),
self.assertEqual(sorted(["tapfoo_id2", "tapfoo_id3",
"tapfoo_id4"]),
sorted(map(str, devices)))
# setting up dhcp for the network
dev_mgr.setup(tests_base.AttributeDict(network))
common_utils.wait_until_true(
lambda: 1 == len(ipw.get_devices()),
lambda: 2 == len(ipw.get_devices()),
timeout=5,
sleep=0.1,
exception=RuntimeError("only one non-loopback device must remain"))
exception=RuntimeError(
"only two non-loopback devices must remain"))
devices = ipw.get_devices()
self.assertEqual("tapfoo_port_id", devices[0].name)
self.assertCountEqual(["tapfoo_id4", "tapfoo_id"],
[d.name for d in devices])