nm.device: Deletion: Assume removed interface as success

Instead of making various and wrong assumption in
`_delete_device_callback()` which errors mean that the interface is
removed, just check if the interface is not there anymore. This will
also handle failures like `nm-device-error-quark: This device is not a
software device or is not realized (5)` or `error=nm-client-error-quark:
Object is no longer in the client cache (0)` that were not caught by the
previous code. When these errors happened or probably when
`NMDevice.is_real()` returns `False`, `NMDevice.get_iface()` returns
`None`. Therefore get the interface earlier to have it available in the
callback. A better solution might be to refactor Nmstate to properly
pass a context about which part of the desired state is handled in each
async call to ensure the interface name and possibly other useful
information is always present.

Signed-off-by: Till Maas <opensource@till.name>
This commit is contained in:
Till Maas 2019-12-13 14:07:06 +01:00
parent 5096f56d64
commit 82574ec3a4

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2018-2019 Red Hat, Inc.
# Copyright (c) 2018-2020 Red Hat, Inc.
#
# This file is part of nmstate
#
@ -173,62 +173,37 @@ def delete_device(nmdev):
def _safe_delete_device_async(nmdev):
mainloop = nmclient.mainloop()
user_data = mainloop, nmdev
user_data = mainloop, nmdev, nmdev.get_iface()
nmdev.delete_async(
mainloop.cancellable, _delete_device_callback, user_data
)
def _delete_device_callback(src_object, result, user_data):
mainloop, nmdev = user_data
mainloop, nmdev, iface = user_data
error = None
try:
success = src_object.delete_finish(result)
# pylint: disable=catching-non-exception
except nmclient.GLib.GError as e:
# pylint: enable=catching-non-exception
if e.matches(
nmclient.Gio.DBusError.quark(),
nmclient.Gio.DBusError.UNKNOWN_METHOD,
) or (
e.matches(
nmclient.NM.DeviceError.quark(),
nmclient.NM.DeviceError.NOTSOFTWARE,
)
and nmdev.is_software()
):
logging.debug(
"Device %s has been already deleted: error=%s",
nmdev.get_iface(),
e,
)
mainloop.execute_next_action()
else:
mainloop.quit(
"Device deletion failed on {}: error={}".format(
nmdev.get_iface(), e
)
)
return
src_object.delete_finish(result)
except Exception as e:
if mainloop.is_action_canceled(e):
error = e
if mainloop.is_action_canceled(error):
logging.debug(
"Device deletion aborted on %s: error=%s", nmdev.get_iface(), e
"Device deletion aborted on %s: error=%s", iface, error
)
return
if not nmdev.is_real():
logging.debug("Interface is not real anymore: iface=%s", iface)
if error:
logging.debug(
"Ignored error: %s", error,
)
else:
mainloop.quit(
"Device deletion failed on {}: error={}".format(
nmdev.get_iface(), e
)
)
return
devname = src_object.get_iface()
if success:
logging.debug("Device deletion succeeded: dev=%s", devname)
mainloop.execute_next_action()
else:
mainloop.quit(
"Device deletion failed: dev={}, error=unknown".format(devname)
f"Device deletion failed on {iface} ({nmdev.get_path()}): "
f"error={error or 'unknown'}"
)