summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Moser <smoser@ubuntu.com>2018-03-16 15:43:27 -0600
committerChad Smith <chad.smith@canonical.com>2018-03-16 15:43:27 -0600
commitde34dc7c467b318b2d04d065f8d752c7a530e155 (patch)
tree768e0401dcdb4d6c428b516abe853bfbd8a3086a
parent7ce839f846de705980839f9c7851bd0fd7353aad (diff)
downloadvyos-cloud-init-de34dc7c467b318b2d04d065f8d752c7a530e155.tar.gz
vyos-cloud-init-de34dc7c467b318b2d04d065f8d752c7a530e155.zip
net: recognize iscsi root cases without ip= on kernel command line.
When 'ip=' or 'ip6=' is found on the kernel command line, cloud-init will consider read network config from /run/net-*.conf files. There are some iscsi-root scenarios where initramfs configures networking but the ip= parameter is not present. 2 such cases are:  a.) static config in /etc/iscsi/iscsi.initramfs (copied into the initramfs)  b.) iBft This changes cloud-init to consider initramfs provided networking information if:  * there are /run/net-* files and  * (ip= or ip6 is on the command line) or open-iscsi.interface file exists. LP: #1752391
-rwxr-xr-xcloudinit/net/cmdline.py24
-rw-r--r--cloudinit/tests/helpers.py9
-rw-r--r--tests/unittests/test_net.py61
3 files changed, 72 insertions, 22 deletions
diff --git a/cloudinit/net/cmdline.py b/cloudinit/net/cmdline.py
index 7b2cc9db..9e9fe0fe 100755
--- a/cloudinit/net/cmdline.py
+++ b/cloudinit/net/cmdline.py
@@ -9,12 +9,15 @@ import base64
import glob
import gzip
import io
+import os
from . import get_devicelist
from . import read_sys_net_safe
from cloudinit import util
+_OPEN_ISCSI_INTERFACE_FILE = "/run/initramfs/open-iscsi.interface"
+
def _klibc_to_config_entry(content, mac_addrs=None):
"""Convert a klibc written shell content file to a 'config' entry
@@ -103,9 +106,13 @@ def _klibc_to_config_entry(content, mac_addrs=None):
return name, iface
+def _get_klibc_net_cfg_files():
+ return glob.glob('/run/net-*.conf') + glob.glob('/run/net6-*.conf')
+
+
def config_from_klibc_net_cfg(files=None, mac_addrs=None):
if files is None:
- files = glob.glob('/run/net-*.conf') + glob.glob('/run/net6-*.conf')
+ files = _get_klibc_net_cfg_files()
entries = []
names = {}
@@ -160,10 +167,23 @@ def _b64dgz(b64str, gzipped="try"):
return _decomp_gzip(blob, strict=gzipped != "try")
+def _is_initramfs_netconfig(files, cmdline):
+ if files:
+ if 'ip=' in cmdline or 'ip6=' in cmdline:
+ return True
+ if os.path.exists(_OPEN_ISCSI_INTERFACE_FILE):
+ # iBft can configure networking without ip=
+ return True
+ return False
+
+
def read_kernel_cmdline_config(files=None, mac_addrs=None, cmdline=None):
if cmdline is None:
cmdline = util.get_cmdline()
+ if files is None:
+ files = _get_klibc_net_cfg_files()
+
if 'network-config=' in cmdline:
data64 = None
for tok in cmdline.split():
@@ -172,7 +192,7 @@ def read_kernel_cmdline_config(files=None, mac_addrs=None, cmdline=None):
if data64:
return util.load_yaml(_b64dgz(data64))
- if 'ip=' not in cmdline and 'ip6=' not in cmdline:
+ if not _is_initramfs_netconfig(files, cmdline):
return None
if mac_addrs is None:
diff --git a/cloudinit/tests/helpers.py b/cloudinit/tests/helpers.py
index a2e10536..999b1d7c 100644
--- a/cloudinit/tests/helpers.py
+++ b/cloudinit/tests/helpers.py
@@ -283,10 +283,15 @@ class FilesystemMockingTestCase(ResourceUsingTestCase):
def patchOS(self, new_root):
patch_funcs = {
os.path: [('isfile', 1), ('exists', 1),
- ('islink', 1), ('isdir', 1)],
+ ('islink', 1), ('isdir', 1), ('lexists', 1)],
os: [('listdir', 1), ('mkdir', 1),
- ('lstat', 1), ('symlink', 2)],
+ ('lstat', 1), ('symlink', 2)]
}
+
+ if hasattr(os, 'scandir'):
+ # py27 does not have scandir
+ patch_funcs[os].append(('scandir', 1))
+
for (mod, funcs) in patch_funcs.items():
for f, nargs in funcs:
func = getattr(mod, f)
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index 9cf11f2e..84a0eabf 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -12,10 +12,8 @@ from cloudinit.sources.helpers import openstack
from cloudinit import temp_utils
from cloudinit import util
-from cloudinit.tests.helpers import CiTestCase
-from cloudinit.tests.helpers import dir2dict
-from cloudinit.tests.helpers import mock
-from cloudinit.tests.helpers import populate_dir
+from cloudinit.tests.helpers import (
+ CiTestCase, FilesystemMockingTestCase, dir2dict, mock, populate_dir)
import base64
import copy
@@ -2186,27 +2184,49 @@ class TestCmdlineConfigParsing(CiTestCase):
self.assertEqual(found, self.simple_cfg)
-class TestCmdlineReadKernelConfig(CiTestCase):
+class TestCmdlineReadKernelConfig(FilesystemMockingTestCase):
macs = {
'eth0': '14:02:ec:42:48:00',
'eno1': '14:02:ec:42:48:01',
}
- def test_ip_cmdline_read_kernel_cmdline_ip(self):
- content = {'net-eth0.conf': DHCP_CONTENT_1}
- files = sorted(populate_dir(self.tmp_dir(), content))
+ def test_ip_cmdline_without_ip(self):
+ content = {'/run/net-eth0.conf': DHCP_CONTENT_1,
+ cmdline._OPEN_ISCSI_INTERFACE_FILE: "eth0\n"}
+ exp1 = copy.deepcopy(DHCP_EXPECTED_1)
+ exp1['mac_address'] = self.macs['eth0']
+
+ root = self.tmp_dir()
+ populate_dir(root, content)
+ self.reRoot(root)
+
found = cmdline.read_kernel_cmdline_config(
- files=files, cmdline='foo ip=dhcp', mac_addrs=self.macs)
+ cmdline='foo root=/root/bar', mac_addrs=self.macs)
+ self.assertEqual(found['version'], 1)
+ self.assertEqual(found['config'], [exp1])
+
+ def test_ip_cmdline_read_kernel_cmdline_ip(self):
+ content = {'/run/net-eth0.conf': DHCP_CONTENT_1}
exp1 = copy.deepcopy(DHCP_EXPECTED_1)
exp1['mac_address'] = self.macs['eth0']
+
+ root = self.tmp_dir()
+ populate_dir(root, content)
+ self.reRoot(root)
+
+ found = cmdline.read_kernel_cmdline_config(
+ cmdline='foo ip=dhcp', mac_addrs=self.macs)
self.assertEqual(found['version'], 1)
self.assertEqual(found['config'], [exp1])
def test_ip_cmdline_read_kernel_cmdline_ip6(self):
- content = {'net6-eno1.conf': DHCP6_CONTENT_1}
- files = sorted(populate_dir(self.tmp_dir(), content))
+ content = {'/run/net6-eno1.conf': DHCP6_CONTENT_1}
+ root = self.tmp_dir()
+ populate_dir(root, content)
+ self.reRoot(root)
+
found = cmdline.read_kernel_cmdline_config(
- files=files, cmdline='foo ip6=dhcp root=/dev/sda',
+ cmdline='foo ip6=dhcp root=/dev/sda',
mac_addrs=self.macs)
self.assertEqual(
found,
@@ -2226,18 +2246,23 @@ class TestCmdlineReadKernelConfig(CiTestCase):
self.assertIsNone(found)
def test_ip_cmdline_both_ip_ip6(self):
- content = {'net-eth0.conf': DHCP_CONTENT_1,
- 'net6-eth0.conf': DHCP6_CONTENT_1.replace('eno1', 'eth0')}
- files = sorted(populate_dir(self.tmp_dir(), content))
- found = cmdline.read_kernel_cmdline_config(
- files=files, cmdline='foo ip=dhcp ip6=dhcp', mac_addrs=self.macs)
-
+ content = {
+ '/run/net-eth0.conf': DHCP_CONTENT_1,
+ '/run/net6-eth0.conf': DHCP6_CONTENT_1.replace('eno1', 'eth0')}
eth0 = copy.deepcopy(DHCP_EXPECTED_1)
eth0['mac_address'] = self.macs['eth0']
eth0['subnets'].append(
{'control': 'manual', 'type': 'dhcp6',
'netmask': '64', 'dns_nameservers': ['2001:67c:1562:8010::2:1']})
expected = [eth0]
+
+ root = self.tmp_dir()
+ populate_dir(root, content)
+ self.reRoot(root)
+
+ found = cmdline.read_kernel_cmdline_config(
+ cmdline='foo ip=dhcp ip6=dhcp', mac_addrs=self.macs)
+
self.assertEqual(found['version'], 1)
self.assertEqual(found['config'], expected)