diff options
Diffstat (limited to 'cloudinit/sources/DataSourceLXD.py')
-rw-r--r-- | cloudinit/sources/DataSourceLXD.py | 75 |
1 files changed, 52 insertions, 23 deletions
diff --git a/cloudinit/sources/DataSourceLXD.py b/cloudinit/sources/DataSourceLXD.py index 732b32ff..55ae52a2 100644 --- a/cloudinit/sources/DataSourceLXD.py +++ b/cloudinit/sources/DataSourceLXD.py @@ -10,6 +10,7 @@ Notes: * TODO( Hotplug support using websockets API 1.0/events ) """ +from json.decoder import JSONDecodeError import os import requests @@ -41,14 +42,16 @@ LXD_SOCKET_API_VERSION = "1.0" # Config key mappings to alias as top-level instance data keys CONFIG_KEY_ALIASES = { + "cloud-init.user-data": "user-data", + "cloud-init.network-config": "network-config", + "cloud-init.vendor-data": "vendor-data", "user.user-data": "user-data", "user.network-config": "network-config", - "user.network_mode": "network_mode", "user.vendor-data": "vendor-data" } -def generate_fallback_network_config(network_mode: str = "") -> dict: +def generate_fallback_network_config() -> dict: """Return network config V1 dict representing instance network config.""" network_v1 = { "version": 1, @@ -76,12 +79,6 @@ def generate_fallback_network_config(network_mode: str = "") -> dict: network_v1["config"][0]["name"] = "enc9" else: network_v1["config"][0]["name"] = "enp5s0" - if network_mode == "link-local": - network_v1["config"][0]["subnets"][0]["control"] = "manual" - elif network_mode not in ("", "dhcp"): - LOG.warning( - "Ignoring unexpected value user.network_mode: %s", network_mode - ) return network_v1 @@ -244,10 +241,7 @@ class DataSourceLXD(sources.DataSource): "network-config" ) else: - network_mode = self._crawled_metadata.get("network_mode", "") - self._network_config = generate_fallback_network_config( - network_mode - ) + self._network_config = generate_fallback_network_config() return self._network_config @@ -294,7 +288,7 @@ def read_metadata( with requests.Session() as session: session.mount(version_url, LXDSocketAdapter()) # Raw meta-data as text - md_route = "{route}/meta-data".format(route=version_url) + md_route = "{route}meta-data".format(route=version_url) response = session.get(md_route) LOG.debug("[GET] [HTTP:%d] %s", response.status_code, md_route) if not response.ok: @@ -302,7 +296,7 @@ def read_metadata( "Invalid HTTP response [{code}] from {route}: {resp}".format( code=response.status_code, route=md_route, - resp=response.txt + resp=response.text ) ) @@ -310,19 +304,42 @@ def read_metadata( if metadata_only: return md # Skip network-data, vendor-data, user-data - config_url = version_url + "config" - # Represent all advertized/available config routes under - # the dict path {LXD_SOCKET_API_VERSION: {config: {...}}. - LOG.debug("[GET] %s", config_url) - config_routes = session.get(config_url).json() md[LXD_SOCKET_API_VERSION] = { "config": {}, "meta-data": md["meta-data"] } - for config_route in config_routes: + + config_url = version_url + "config" + # Represent all advertized/available config routes under + # the dict path {LXD_SOCKET_API_VERSION: {config: {...}}. + response = session.get(config_url) + LOG.debug("[GET] [HTTP:%d] %s", response.status_code, config_url) + if not response.ok: + raise sources.InvalidMetaDataException( + "Invalid HTTP response [{code}] from {route}: {resp}".format( + code=response.status_code, + route=config_url, + resp=response.text + ) + ) + try: + config_routes = response.json() + except JSONDecodeError as exc: + raise sources.InvalidMetaDataException( + "Unable to determine cloud-init config from {route}." + " Expected JSON but found: {resp}".format( + route=config_url, + resp=response.text + ) + ) from exc + + # Sorting keys to ensure we always process in alphabetical order. + # cloud-init.* keys will sort before user.* keys which is preferred + # precedence. + for config_route in sorted(config_routes): url = "http://lxd{route}".format(route=config_route) - LOG.debug("[GET] %s", url) response = session.get(url) + LOG.debug("[GET] [HTTP:%d] %s", response.status_code, url) if response.ok: cfg_key = config_route.rpartition("/")[-1] # Leave raw data values/format unchanged to represent it in @@ -331,9 +348,21 @@ def read_metadata( md[LXD_SOCKET_API_VERSION]["config"][cfg_key] = response.text # Promote common CONFIG_KEY_ALIASES to top-level keys. if cfg_key in CONFIG_KEY_ALIASES: - md[CONFIG_KEY_ALIASES[cfg_key]] = response.text + # Due to sort of config_routes, promote cloud-init.* + # aliases before user.*. This allows user.* keys to act as + # fallback config on old LXD, with new cloud-init images. + if CONFIG_KEY_ALIASES[cfg_key] not in md: + md[CONFIG_KEY_ALIASES[cfg_key]] = response.text + else: + LOG.warning( + "Ignoring LXD config %s in favor of %s value.", + cfg_key, cfg_key.replace("user", "cloud-init", 1) + ) else: - LOG.debug("Skipping %s on invalid response", url) + LOG.debug( + "Skipping %s on [HTTP:%d]:%s", + url, response.status_code, response.text + ) return md |