diff options
author | Chad Smith <chad.smith@canonical.com> | 2020-03-04 13:53:19 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-04 13:53:19 -0700 |
commit | 1d2dfc5d879dc905f440697c2b805c9485dda821 (patch) | |
tree | d65cbc78f93f47d57602508fc3403cd2fcb406e2 | |
parent | fa1abfec27050a4fb71cad950a17e42f9b43b478 (diff) | |
download | vyos-cloud-init-1d2dfc5d879dc905f440697c2b805c9485dda821.tar.gz vyos-cloud-init-1d2dfc5d879dc905f440697c2b805c9485dda821.zip |
net: support network-config:disabled on the kernel commandline (#232)
Allow disabling cloud-init's network configuration via a plain-text kernel cmdline
Cloud-init docs indicate that users can disable cloud-init networking via kernel
command line parameter 'network-config=<YAML>'. This does not work unless
the <YAML> payload base64 encoded. Document the base64 encoding
requirement and add a plain-text value for disabling cloud-init network config:
network-config=disabled
Also:
- Log an error and ignore any plain-text network-config payloads that are
not specifically 'network-config=disabled'.
- Log a warning if network-config kernel param is invalid yaml but do not
raise an exception, allowing boot to continue and use fallback networking.
LP: #1862702
-rwxr-xr-x | cloudinit/net/cmdline.py | 34 | ||||
-rw-r--r-- | doc/rtd/topics/network-config.rst | 22 | ||||
-rw-r--r-- | tests/unittests/test_net.py | 17 |
3 files changed, 51 insertions, 22 deletions
diff --git a/cloudinit/net/cmdline.py b/cloudinit/net/cmdline.py index 64e1c699..814ce411 100755 --- a/cloudinit/net/cmdline.py +++ b/cloudinit/net/cmdline.py @@ -10,6 +10,7 @@ import base64 import glob import gzip import io +import logging import os from cloudinit import util @@ -19,6 +20,8 @@ from . import read_sys_net_safe _OPEN_ISCSI_INTERFACE_FILE = "/run/initramfs/open-iscsi.interface" +KERNEL_CMDLINE_NETWORK_CONFIG_DISABLED = "disabled" + class InitramfsNetworkConfigSource(metaclass=abc.ABCMeta): """ABC for net config sources that read config written by initramfses""" @@ -233,34 +236,35 @@ def read_initramfs_config(): return None -def _decomp_gzip(blob, strict=True): - # decompress blob. raise exception if not compressed unless strict=False. +def _decomp_gzip(blob): + # decompress blob or return original blob with io.BytesIO(blob) as iobuf: gzfp = None try: gzfp = gzip.GzipFile(mode="rb", fileobj=iobuf) return gzfp.read() except IOError: - if strict: - raise return blob finally: if gzfp: gzfp.close() -def _b64dgz(b64str, gzipped="try"): - # decode a base64 string. If gzipped is true, transparently uncompresss - # if gzipped is 'try', then try gunzip, returning the original on fail. - try: - blob = base64.b64decode(b64str) - except TypeError: - raise ValueError("Invalid base64 text: %s" % b64str) +def _b64dgz(data): + """Decode a string base64 encoding, if gzipped, uncompress as well - if not gzipped: - return blob + :return: decompressed unencoded string of the data or empty string on + unencoded data. + """ + try: + blob = base64.b64decode(data) + except (TypeError, ValueError): + logging.error( + "Expected base64 encoded kernel commandline parameter" + " network-config. Ignoring network-config=%s.", data) + return '' - return _decomp_gzip(blob, strict=gzipped != "try") + return _decomp_gzip(blob) def read_kernel_cmdline_config(cmdline=None): @@ -273,6 +277,8 @@ def read_kernel_cmdline_config(cmdline=None): if tok.startswith("network-config="): data64 = tok.split("=", 1)[1] if data64: + if data64 == KERNEL_CMDLINE_NETWORK_CONFIG_DISABLED: + return {"config": "disabled"} return util.load_yaml(_b64dgz(data64)) return None diff --git a/doc/rtd/topics/network-config.rst b/doc/rtd/topics/network-config.rst index 1520ba9a..0144dfae 100644 --- a/doc/rtd/topics/network-config.rst +++ b/doc/rtd/topics/network-config.rst @@ -25,17 +25,23 @@ For example, OpenStack may provide network config in the MetaData Service. **System Config** -A ``network:`` entry in /etc/cloud/cloud.cfg.d/* configuration files. +A ``network:`` entry in ``/etc/cloud/cloud.cfg.d/*`` configuration files. **Kernel Command Line** -``ip=`` or ``network-config=<YAML config string>`` +``ip=`` or ``network-config=<Base64 encoded YAML config string>`` User-data cannot change an instance's network configuration. In the absence of network configuration in any of the above sources , `Cloud-init`_ will write out a network configuration that will issue a DHCP request on a "first" network interface. +.. note:: + + The network-config value is expected to be a Base64 encoded YAML string in + :ref:`network_config_v1` or :ref:`network_config_v2` format. Optionally it + can be compressed with ``gzip`` prior to Base64 encoding. + Disabling Network Configuration =============================== @@ -48,19 +54,19 @@ on other methods, such as embedded configuration or other customizations. **Kernel Command Line** -`Cloud-init`_ will check for a parameter ``network-config`` and the -value is expected to be YAML string in the :ref:`network_config_v1` format. -The YAML string may optionally be ``Base64`` encoded, and optionally -compressed with ``gzip``. +`Cloud-init`_ will check additionally check for the parameter +``network-config=disabled`` which will automatically disable any network +configuration. Example disabling kernel command line entry: :: - network-config={config: disabled} + network-config=disabled **cloud config** -In the combined cloud-init configuration dictionary. :: +In the combined cloud-init configuration dictionary, merged from +``/etc/cloud/cloud.cfg`` and ``/etc/cloud/cloud.cfg.d/*``:: network: config: disabled diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py index bedd05fe..e03857c4 100644 --- a/tests/unittests/test_net.py +++ b/tests/unittests/test_net.py @@ -4017,6 +4017,8 @@ class TestEniNetworkStateToEni(CiTestCase): class TestCmdlineConfigParsing(CiTestCase): + with_logs = True + simple_cfg = { 'config': [{"type": "physical", "name": "eth0", "mac_address": "c0:d6:9f:2c:e8:80", @@ -4066,6 +4068,21 @@ class TestCmdlineConfigParsing(CiTestCase): found = cmdline.read_kernel_cmdline_config(cmdline=raw_cmdline) self.assertEqual(found, self.simple_cfg) + def test_cmdline_with_net_config_disabled(self): + raw_cmdline = 'ro network-config=disabled root=foo' + found = cmdline.read_kernel_cmdline_config(cmdline=raw_cmdline) + self.assertEqual(found, {'config': 'disabled'}) + + def test_cmdline_with_net_config_unencoded_logs_error(self): + """network-config cannot be unencoded besides 'disabled'.""" + raw_cmdline = 'ro network-config={config:disabled} root=foo' + found = cmdline.read_kernel_cmdline_config(cmdline=raw_cmdline) + self.assertIsNone(found) + expected_log = ( + 'ERROR: Expected base64 encoded kernel commandline parameter' + ' network-config. Ignoring network-config={config:disabled}.') + self.assertIn(expected_log, self.logs.getvalue()) + def test_cmdline_with_b64_gz(self): data = _gzip_data(json.dumps(self.simple_cfg).encode()) encoded_text = base64.b64encode(data).decode() |