Skip to content

Commit

Permalink
tried adding _perform_connectivity_check to ephemeral ip
Browse files Browse the repository at this point in the history
  • Loading branch information
a-dubs committed Oct 22, 2024
1 parent cdc2fb8 commit 16d2927
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 46 deletions.
76 changes: 49 additions & 27 deletions cloudinit/net/ephemeral.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""Module for ephemeral network context managers
"""
import contextlib
import json
import logging
from functools import partial
from typing import Any, Callable, Dict, List, Optional, Tuple
Expand All @@ -11,6 +12,7 @@
import cloudinit.netinfo as netinfo
from cloudinit.net.dhcp import NoDHCPLeaseError, maybe_perform_dhcp_discovery
from cloudinit.subp import ProcessExecutionError
from cloudinit.url_helper import UrlError, wait_for_url

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -405,7 +407,6 @@ def __init__(
ipv6: bool = False,
ipv4: bool = True,
connectivity_urls_data: Optional[List[Dict[str, Any]]] = None,
ipv6_connectivity_check_callback: Optional[Callable] = None,
):
"""
Args:
Expand All @@ -429,12 +430,9 @@ def __init__(
self.state_msg: str = ""
self.distro = distro
self.connectivity_urls_data = connectivity_urls_data
self.ipv6_connectivity_check_callback = (
ipv6_connectivity_check_callback
)

# will be updated by the context manager
self.ipv6_reached_at_url = None
self.imds_reached_at_url: Optional[str] = None

def __enter__(self):
if not (self.ipv4 or self.ipv6):
Expand All @@ -444,27 +442,12 @@ def __enter__(self):
exceptions = []
ephemeral_obtained = False

if self.ipv6_connectivity_check_callback is not None:
if not self.ipv6:
raise ValueError(
"ipv6_connectivity_check_callback provided but ipv6 is "
"not enabled"
)
ephemeral_obtained, exceptions = self._do_ipv6(
ephemeral_obtained, exceptions
)
self.ipv6_reached_at_url = self.ipv6_connectivity_check_callback()
# if ipv6_connectivity_check_callback is provided, then we want to
# skip ipv4 ephemeral network setup if ipv6 ephemeral network setup
# and imds connectivity check succeeded
if self.ipv4 and not self.ipv6_reached_at_url:
LOG.debug(
"Bringing up ipv4 ephemeral network since ipv6 failed"
)
ephemeral_obtained, exceptions = self._do_ipv4(
ephemeral_obtained, exceptions
)
self.imds_reached_at_url = self._perform_connectivity_check()

if self.imds_reached_at_url:
LOG.debug("We already have connectivity to IMDS, skipping DHCP.")
else:
LOG.debug("No connectivity to IMDS, attempting DHCP setup.")
if self.ipv4:
ephemeral_obtained, exceptions = self._do_ipv4(
ephemeral_obtained, exceptions
Expand All @@ -474,7 +457,7 @@ def __enter__(self):
ephemeral_obtained, exceptions
)

if not ephemeral_obtained:
if not self.imds_reached_at_url and not ephemeral_obtained:
# Ephemeral network setup failed in linkup for both ipv4 and
# ipv6. Raise only the first exception found.
LOG.error(
Expand Down Expand Up @@ -504,7 +487,6 @@ def _do_ipv4(
EphemeralDHCPv4(
distro=self.distro,
iface=self.interface,
connectivity_urls_data=self.connectivity_urls_data,
)
)
ephemeral_obtained = True
Expand Down Expand Up @@ -561,5 +543,45 @@ def _do_ipv6(
exceptions.append(e)
return ephemeral_obtained, exceptions

def _perform_connectivity_check(
self,
) -> Optional[str]:

def headers_cb(url):
headers = [
url_data.get("headers") for url_data in self.connectivity_urls_data
if url_data["url"] == url
][0]
return headers

try:
url_that_worked, url_response = wait_for_url(
urls=[url_data["url"] for url_data in self.connectivity_urls_data],
headers_cb=headers_cb,
timeout=0.5, # keep really short for quick failure path
connect_synchronously=False,
)
imds_data = json.loads(url_response.decode("utf-8"))
except UrlError as e:
LOG.debug(
"Failed to reach IMDS with error: %s",
e,
)
except Exception as e: # pylint: disable=broad-except
LOG.debug(
"Unexpected error occurred. Failed to reach IMDS: %s",
e,
)
else:
if imds_data:
LOG.debug(
"IMDS was successfully reached at %s without ephemeral "
"network setup.",
url_that_worked,
)
return url_that_worked
LOG.debug("Failed to reach IMDS without ephemeral network setup.")
return None

def __exit__(self, *_args):
self.stack.close()
37 changes: 18 additions & 19 deletions cloudinit/sources/DataSourceOracle.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,6 @@
IPV6_METADATA_ROOT = "http://[fd00:c1::a9fe:a9fe]/opc/v{version}/"
IPV4_METADATA_PATTERN = IPV4_METADATA_ROOT + "{path}/"
IPV6_METADATA_PATTERN = IPV6_METADATA_ROOT + "{path}/"
METADATA_URLS = [
IPV4_METADATA_ROOT,
IPV6_METADATA_ROOT,
]
METADATA_ROOTS = [
IPV4_METADATA_ROOT,
IPV6_METADATA_ROOT,
]

# https://docs.cloud.oracle.com/iaas/Content/Network/Troubleshoot/connectionhang.htm#Overview,
# indicates that an MTU of 9000 is used within OCI
Expand Down Expand Up @@ -196,26 +188,29 @@ def _get_data(self):
version=1, path="instance"
),
},
{
"url": IPV6_METADATA_PATTERN.format(
version=2, path="instance"
),
"headers": V2_HEADERS,
},
{
"url": IPV6_METADATA_PATTERN.format(
version=1, path="instance"
),
},
]

ipv6_url_that_worked = check_ipv6_connectivity()
if ipv6_url_that_worked:
md_patterns = [IPV6_METADATA_PATTERN]
else:
md_patterns = [IPV4_METADATA_PATTERN]

# if we have connectivity to imds, then skip ephemeral network setup
if self.perform_dhcp_setup and not ipv6_url_that_worked:
if self.perform_dhcp_setup:

nic_name = net.find_fallback_nic()
try:
network_context = ephemeral.EphemeralIPNetwork(
distro=self.distro,
interface=nic_name,
ipv6=False,
ipv6=True,
ipv4=True,
connectivity_urls_data=connectivity_urls_data,
ipv6_connectivity_check_callback=None,
)
except Exception:
network_context = util.nullcontext()
Expand All @@ -232,7 +227,10 @@ def _get_data(self):
fetch_vnics_data=fetch_primary_nic or fetch_secondary_nics,
max_wait=self.url_max_wait,
timeout=self.url_timeout,
metadata_patterns=md_patterns,
metadata_patterns=[
IPV6_METADATA_PATTERN,
IPV4_METADATA_PATTERN,
],
)
# set the metadata root address that worked to allow for detecting
# whether ipv4 or ipv6 was used for getting metadata
Expand Down Expand Up @@ -557,6 +555,7 @@ def read_opc_metadata(
timeout=timeout,
headers_cb=_headers_cb,
sleep_time=0.1,
connect_synchronously=False,
)
if vnics_url:
vnics_data = json.loads(vnics_response.decode("utf-8"))
Expand Down

0 comments on commit 16d2927

Please sign in to comment.