Merge ~smoser/cloud-init:bug/1752391-fix-iscsi-root-without-ip into cloud-init:master

Proposed by Scott Moser
Status: Merged
Approved by: Chad Smith
Approved revision: 7428655537de85f2c0732862402391736c765dbe
Merge reported by: Chad Smith
Merged at revision: de34dc7c467b318b2d04d065f8d752c7a530e155
Proposed branch: ~smoser/cloud-init:bug/1752391-fix-iscsi-root-without-ip
Merge into: cloud-init:master
Diff against target: 194 lines (+72/-22)
3 files modified
cloudinit/net/cmdline.py (+22/-2)
cloudinit/tests/helpers.py (+7/-2)
tests/unittests/test_net.py (+43/-18)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Chad Smith Approve
Review via email: mp+340140@code.launchpad.net

Commit message

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

Description of the change

see commit message

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:11f8aa59eea1fd06098c9e2e11e95b5578774b53
https://jenkins.ubuntu.com/server/job/cloud-init-ci/797/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Unit & Style Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/797/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:54eb8eedccfbe8a1e9a33365b1f44228bd58a427
https://jenkins.ubuntu.com/server/job/cloud-init-ci/799/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    SUCCESS: MAAS Compatability Testing
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/799/rebuild

review: Approve (continuous-integration)
Revision history for this message
Ryan Harper (raharper) :
Revision history for this message
Scott Moser (smoser) :
Revision history for this message
Chad Smith (chad.smith) wrote :

Minor nit inline about the commandline ip6= match. but looks good.

review: Approve
Revision history for this message
Scott Moser (smoser) :
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

FAILED: Continuous integration, rev:7428655537de85f2c0732862402391736c765dbe
https://jenkins.ubuntu.com/server/job/cloud-init-ci/875/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Unit & Style Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/875/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:8c114967f21112ab3dec1cc3a647556f766ba66a
https://jenkins.ubuntu.com/server/job/cloud-init-ci/876/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    SUCCESS: MAAS Compatability Testing
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/876/rebuild

review: Approve (continuous-integration)
Revision history for this message
Chad Smith (chad.smith) wrote :

An upstream commit landed for this bug.

To view that commit see the following URL:
https://git.launchpad.net/cloud-init/commit/?id=de34dc7c

There was an error fetching revisions from git servers. Please try again in a few minutes. If the problem persists, contact Launchpad support.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/cloudinit/net/cmdline.py b/cloudinit/net/cmdline.py
index 7b2cc9d..9e9fe0f 100755
--- a/cloudinit/net/cmdline.py
+++ b/cloudinit/net/cmdline.py
@@ -9,12 +9,15 @@ import base64
9import glob9import glob
10import gzip10import gzip
11import io11import io
12import os
1213
13from . import get_devicelist14from . import get_devicelist
14from . import read_sys_net_safe15from . import read_sys_net_safe
1516
16from cloudinit import util17from cloudinit import util
1718
19_OPEN_ISCSI_INTERFACE_FILE = "/run/initramfs/open-iscsi.interface"
20
1821
19def _klibc_to_config_entry(content, mac_addrs=None):22def _klibc_to_config_entry(content, mac_addrs=None):
20 """Convert a klibc written shell content file to a 'config' entry23 """Convert a klibc written shell content file to a 'config' entry
@@ -103,9 +106,13 @@ def _klibc_to_config_entry(content, mac_addrs=None):
103 return name, iface106 return name, iface
104107
105108
109def _get_klibc_net_cfg_files():
110 return glob.glob('/run/net-*.conf') + glob.glob('/run/net6-*.conf')
111
112
106def config_from_klibc_net_cfg(files=None, mac_addrs=None):113def config_from_klibc_net_cfg(files=None, mac_addrs=None):
107 if files is None:114 if files is None:
108 files = glob.glob('/run/net-*.conf') + glob.glob('/run/net6-*.conf')115 files = _get_klibc_net_cfg_files()
109116
110 entries = []117 entries = []
111 names = {}118 names = {}
@@ -160,10 +167,23 @@ def _b64dgz(b64str, gzipped="try"):
160 return _decomp_gzip(blob, strict=gzipped != "try")167 return _decomp_gzip(blob, strict=gzipped != "try")
161168
162169
170def _is_initramfs_netconfig(files, cmdline):
171 if files:
172 if 'ip=' in cmdline or 'ip6=' in cmdline:
173 return True
174 if os.path.exists(_OPEN_ISCSI_INTERFACE_FILE):
175 # iBft can configure networking without ip=
176 return True
177 return False
178
179
163def read_kernel_cmdline_config(files=None, mac_addrs=None, cmdline=None):180def read_kernel_cmdline_config(files=None, mac_addrs=None, cmdline=None):
164 if cmdline is None:181 if cmdline is None:
165 cmdline = util.get_cmdline()182 cmdline = util.get_cmdline()
166183
184 if files is None:
185 files = _get_klibc_net_cfg_files()
186
167 if 'network-config=' in cmdline:187 if 'network-config=' in cmdline:
168 data64 = None188 data64 = None
169 for tok in cmdline.split():189 for tok in cmdline.split():
@@ -172,7 +192,7 @@ def read_kernel_cmdline_config(files=None, mac_addrs=None, cmdline=None):
172 if data64:192 if data64:
173 return util.load_yaml(_b64dgz(data64))193 return util.load_yaml(_b64dgz(data64))
174194
175 if 'ip=' not in cmdline and 'ip6=' not in cmdline:195 if not _is_initramfs_netconfig(files, cmdline):
176 return None196 return None
177197
178 if mac_addrs is None:198 if mac_addrs is None:
diff --git a/cloudinit/tests/helpers.py b/cloudinit/tests/helpers.py
index a2e1053..999b1d7 100644
--- a/cloudinit/tests/helpers.py
+++ b/cloudinit/tests/helpers.py
@@ -283,10 +283,15 @@ class FilesystemMockingTestCase(ResourceUsingTestCase):
283 def patchOS(self, new_root):283 def patchOS(self, new_root):
284 patch_funcs = {284 patch_funcs = {
285 os.path: [('isfile', 1), ('exists', 1),285 os.path: [('isfile', 1), ('exists', 1),
286 ('islink', 1), ('isdir', 1)],286 ('islink', 1), ('isdir', 1), ('lexists', 1)],
287 os: [('listdir', 1), ('mkdir', 1),287 os: [('listdir', 1), ('mkdir', 1),
288 ('lstat', 1), ('symlink', 2)],288 ('lstat', 1), ('symlink', 2)]
289 }289 }
290
291 if hasattr(os, 'scandir'):
292 # py27 does not have scandir
293 patch_funcs[os].append(('scandir', 1))
294
290 for (mod, funcs) in patch_funcs.items():295 for (mod, funcs) in patch_funcs.items():
291 for f, nargs in funcs:296 for f, nargs in funcs:
292 func = getattr(mod, f)297 func = getattr(mod, f)
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index 9cf11f2..84a0eab 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -12,10 +12,8 @@ from cloudinit.sources.helpers import openstack
12from cloudinit import temp_utils12from cloudinit import temp_utils
13from cloudinit import util13from cloudinit import util
1414
15from cloudinit.tests.helpers import CiTestCase15from cloudinit.tests.helpers import (
16from cloudinit.tests.helpers import dir2dict16 CiTestCase, FilesystemMockingTestCase, dir2dict, mock, populate_dir)
17from cloudinit.tests.helpers import mock
18from cloudinit.tests.helpers import populate_dir
1917
20import base6418import base64
21import copy19import copy
@@ -2186,27 +2184,49 @@ class TestCmdlineConfigParsing(CiTestCase):
2186 self.assertEqual(found, self.simple_cfg)2184 self.assertEqual(found, self.simple_cfg)
21872185
21882186
2189class TestCmdlineReadKernelConfig(CiTestCase):2187class TestCmdlineReadKernelConfig(FilesystemMockingTestCase):
2190 macs = {2188 macs = {
2191 'eth0': '14:02:ec:42:48:00',2189 'eth0': '14:02:ec:42:48:00',
2192 'eno1': '14:02:ec:42:48:01',2190 'eno1': '14:02:ec:42:48:01',
2193 }2191 }
21942192
2195 def test_ip_cmdline_read_kernel_cmdline_ip(self):2193 def test_ip_cmdline_without_ip(self):
2196 content = {'net-eth0.conf': DHCP_CONTENT_1}2194 content = {'/run/net-eth0.conf': DHCP_CONTENT_1,
2197 files = sorted(populate_dir(self.tmp_dir(), content))2195 cmdline._OPEN_ISCSI_INTERFACE_FILE: "eth0\n"}
2196 exp1 = copy.deepcopy(DHCP_EXPECTED_1)
2197 exp1['mac_address'] = self.macs['eth0']
2198
2199 root = self.tmp_dir()
2200 populate_dir(root, content)
2201 self.reRoot(root)
2202
2198 found = cmdline.read_kernel_cmdline_config(2203 found = cmdline.read_kernel_cmdline_config(
2199 files=files, cmdline='foo ip=dhcp', mac_addrs=self.macs)2204 cmdline='foo root=/root/bar', mac_addrs=self.macs)
2205 self.assertEqual(found['version'], 1)
2206 self.assertEqual(found['config'], [exp1])
2207
2208 def test_ip_cmdline_read_kernel_cmdline_ip(self):
2209 content = {'/run/net-eth0.conf': DHCP_CONTENT_1}
2200 exp1 = copy.deepcopy(DHCP_EXPECTED_1)2210 exp1 = copy.deepcopy(DHCP_EXPECTED_1)
2201 exp1['mac_address'] = self.macs['eth0']2211 exp1['mac_address'] = self.macs['eth0']
2212
2213 root = self.tmp_dir()
2214 populate_dir(root, content)
2215 self.reRoot(root)
2216
2217 found = cmdline.read_kernel_cmdline_config(
2218 cmdline='foo ip=dhcp', mac_addrs=self.macs)
2202 self.assertEqual(found['version'], 1)2219 self.assertEqual(found['version'], 1)
2203 self.assertEqual(found['config'], [exp1])2220 self.assertEqual(found['config'], [exp1])
22042221
2205 def test_ip_cmdline_read_kernel_cmdline_ip6(self):2222 def test_ip_cmdline_read_kernel_cmdline_ip6(self):
2206 content = {'net6-eno1.conf': DHCP6_CONTENT_1}2223 content = {'/run/net6-eno1.conf': DHCP6_CONTENT_1}
2207 files = sorted(populate_dir(self.tmp_dir(), content))2224 root = self.tmp_dir()
2225 populate_dir(root, content)
2226 self.reRoot(root)
2227
2208 found = cmdline.read_kernel_cmdline_config(2228 found = cmdline.read_kernel_cmdline_config(
2209 files=files, cmdline='foo ip6=dhcp root=/dev/sda',2229 cmdline='foo ip6=dhcp root=/dev/sda',
2210 mac_addrs=self.macs)2230 mac_addrs=self.macs)
2211 self.assertEqual(2231 self.assertEqual(
2212 found,2232 found,
@@ -2226,18 +2246,23 @@ class TestCmdlineReadKernelConfig(CiTestCase):
2226 self.assertIsNone(found)2246 self.assertIsNone(found)
22272247
2228 def test_ip_cmdline_both_ip_ip6(self):2248 def test_ip_cmdline_both_ip_ip6(self):
2229 content = {'net-eth0.conf': DHCP_CONTENT_1,2249 content = {
2230 'net6-eth0.conf': DHCP6_CONTENT_1.replace('eno1', 'eth0')}2250 '/run/net-eth0.conf': DHCP_CONTENT_1,
2231 files = sorted(populate_dir(self.tmp_dir(), content))2251 '/run/net6-eth0.conf': DHCP6_CONTENT_1.replace('eno1', 'eth0')}
2232 found = cmdline.read_kernel_cmdline_config(
2233 files=files, cmdline='foo ip=dhcp ip6=dhcp', mac_addrs=self.macs)
2234
2235 eth0 = copy.deepcopy(DHCP_EXPECTED_1)2252 eth0 = copy.deepcopy(DHCP_EXPECTED_1)
2236 eth0['mac_address'] = self.macs['eth0']2253 eth0['mac_address'] = self.macs['eth0']
2237 eth0['subnets'].append(2254 eth0['subnets'].append(
2238 {'control': 'manual', 'type': 'dhcp6',2255 {'control': 'manual', 'type': 'dhcp6',
2239 'netmask': '64', 'dns_nameservers': ['2001:67c:1562:8010::2:1']})2256 'netmask': '64', 'dns_nameservers': ['2001:67c:1562:8010::2:1']})
2240 expected = [eth0]2257 expected = [eth0]
2258
2259 root = self.tmp_dir()
2260 populate_dir(root, content)
2261 self.reRoot(root)
2262
2263 found = cmdline.read_kernel_cmdline_config(
2264 cmdline='foo ip=dhcp ip6=dhcp', mac_addrs=self.macs)
2265
2241 self.assertEqual(found['version'], 1)2266 self.assertEqual(found['version'], 1)
2242 self.assertEqual(found['config'], expected)2267 self.assertEqual(found['config'], expected)
22432268

Subscribers

People subscribed via source and target branches