Skip to content

Commit

Permalink
ephemeral: Handle link up failure for both ipv4 and ipv6
Browse files Browse the repository at this point in the history
EphemeralIPv{4,6} failure is not always an error, therefore do not log
this event as an error in the context manager. Allow callsites to
determine log level.

Fixes canonicalGH-4540
  • Loading branch information
holmanb committed Oct 24, 2023
1 parent 14b76c4 commit 9be8bad
Showing 1 changed file with 49 additions and 19 deletions.
68 changes: 49 additions & 19 deletions cloudinit/net/ephemeral.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,6 @@ def __enter__(self):
elif self.router:
self._bringup_router()
except subp.ProcessExecutionError:
LOG.error(
"Error bringing up EphemeralIPv4Network. "
"Datasource setup cannot continue"
)
self.__exit__(None, None, None)
raise

Expand Down Expand Up @@ -274,11 +270,9 @@ def __exit__(self, excp_type, excp_value, excp_traceback):

def clean_network(self):
"""Exit _ephipv4 context to teardown of ip configuration performed."""
if self.lease:
self.lease = None
if not self._ephipv4:
return
self._ephipv4.__exit__(None, None, None)
self.lease = None
if self._ephipv4:
self._ephipv4.__exit__(None, None, None)

def obtain_lease(self):
"""Perform dhcp discovery in a sandboxed environment if possible.
Expand Down Expand Up @@ -350,7 +344,13 @@ def get_first_option_value(


class EphemeralIPNetwork:
"""Marries together IPv4 and IPv6 ephemeral context managers"""
"""Combined ephemeral context manager for IPv4 and IPv6
Either ipv4 or ipv6 ephemeral network may fail to initialize, but if either
succeeds, then this context manager will not raise exception. This allows
either ipv4 or ipv6 ephemeral network to succeed, but requires that error
handling for networks unavailable be done within the context.
"""

def __init__(
self,
Expand All @@ -367,21 +367,51 @@ def __init__(
self.distro = distro

def __enter__(self):
# ipv6 dualstack might succeed when dhcp4 fails
# therefore catch exception unless only v4 is used
if not (self.ipv4 or self.ipv6):
# no ephemeral network requested, but this object still needs to
# function as a context manager
return self
try:
exceptions = []
ephemeral_obtained = False
if self.ipv4:
self.stack.enter_context(
EphemeralDHCPv4(self.distro, self.interface)
)
try:
self.stack.enter_context(
EphemeralDHCPv4(
self.distro,
self.interface,
)
)
ephemeral_obtained = True
except subp.ProcessExecutionError as e:
LOG.info("Failed to bring up EphemeralIPv4Network.")
exceptions.append(e)

if self.ipv6:
self.stack.enter_context(
EphemeralIPv6Network(self.distro, self.interface)
try:
self.stack.enter_context(
EphemeralIPv6Network(
self.distro,
self.interface,
)
)
ephemeral_obtained = True
except subp.ProcessExecutionError as e:
LOG.info("Failed to bring up EphemeralIPv6Network.")
exceptions.append(e)

if not ephemeral_obtained:
# Ephemeral network setup failed in linkup for both ipv4 and
# ipv6. Raise only the first exception found.
LOG.error(
"Failed to bring up EphemeralIPNetwork. "
"Datasource setup cannot continue"
)
# v6 link local might be usable
# caller may want to log network state
raise exceptions[0]
except NoDHCPLeaseError as e:
if self.ipv6:
# ipv6 dualstack might succeed when dhcp4 fails, so catch
# NoDHCPLeaseError unless only v4 is used
self.state_msg = "using link-local ipv6"
else:
raise e
Expand Down

0 comments on commit 9be8bad

Please sign in to comment.