Merge lp:~ltrager/maas/fix_xenial_net_detect into lp:~maas-committers/maas/trunk

Proposed by Lee Trager
Status: Merged
Approved by: Lee Trager
Approved revision: no longer in the source branch.
Merged at revision: 4524
Proposed branch: lp:~ltrager/maas/fix_xenial_net_detect
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 121 lines (+28/-14)
3 files modified
src/provisioningserver/network.py (+1/-0)
src/provisioningserver/utils/ipaddr.py (+2/-5)
src/provisioningserver/utils/tests/test_ipaddr.py (+25/-9)
To merge this branch: bzr merge lp:~ltrager/maas/fix_xenial_net_detect
Reviewer Review Type Date Requested Status
Mike Pontillo (community) Approve
Review via email: mp+278634@code.launchpad.net

Commit message

Fix cluster controller networking auto detection

* Don't require that a valid NIC has a kernel module loaded
* When falling back to scanning ip addr for devices look for network devices which follow the preedictable network interface names standard.

Description of the change

Auto detection of the cluster controllers network devices was failing for two reasons

1. MAAS's primary method of discovering NICs is to iterate through /sys/class/net. A device was only identified as a physical device that MAAS can use if its /sys entry contained device/driver/module. In Xenial the virtio network driver is built into the kernel thus the module subdirectory doesn't exist. Now we just check that it contains the device in its /sys entry.
2. As a fall back MAAS iterates over the output of ip addr. Xenial is following the preedictable network interface names standard[1] which creates ethernet devices starting with 'en' instead of 'eth'. MAAS was checking for devices that start with 'em' while devices only come up with 'en.' Many articulates on the internet came out describing that 'em' would be used and many still report that today[2]. However the freedesktop.org spec[1] links to a comment in the udev source code[3] which explains how devices will be named starting with 'en'

1. http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/
2. https://en.wikipedia.org/wiki/Consistent_Network_Device_Naming
3. https://github.com/systemd/systemd/blob/master/src/udev/udev-builtin-net_id.c#L20

To post a comment you must log in.
Revision history for this message
Mike Pontillo (mpontillo) wrote :

Looks good, but please keep the startswith('em') in there; that's still a valid for embedded NICs.[1]

[1]:
https://en.wikipedia.org/wiki/Consistent_Network_Device_Naming

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (24.1 KiB)

The attempt to merge lp:~ltrager/maas/fix_xenial_net_detect into lp:maas failed. Below is the output from the failed tests.

Get:1 http://prodstack-zone-1.clouds.archive.ubuntu.com xenial InRelease [218 kB]
Hit http://security.ubuntu.com xenial-security InRelease
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com xenial-updates InRelease
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com xenial-backports InRelease
Hit http://security.ubuntu.com xenial-security/main Sources
Hit http://security.ubuntu.com xenial-security/restricted Sources
Hit http://security.ubuntu.com xenial-security/universe Sources
Hit http://security.ubuntu.com xenial-security/multiverse Sources
Hit http://security.ubuntu.com xenial-security/main amd64 Packages
Hit http://security.ubuntu.com xenial-security/restricted amd64 Packages
Hit http://security.ubuntu.com xenial-security/universe amd64 Packages
Hit http://security.ubuntu.com xenial-security/multiverse amd64 Packages
Hit http://security.ubuntu.com xenial-security/main Translation-en
Hit http://security.ubuntu.com xenial-security/multiverse Translation-en
Hit http://security.ubuntu.com xenial-security/restricted Translation-en
Hit http://security.ubuntu.com xenial-security/universe Translation-en
Get:2 http://prodstack-zone-1.clouds.archive.ubuntu.com xenial/main Sources [1,119 kB]
Get:3 http://prodstack-zone-1.clouds.archive.ubuntu.com xenial/restricted Sources [7,228 B]
Get:4 http://prodstack-zone-1.clouds.archive.ubuntu.com xenial/universe Sources [7,487 kB]
Get:5 http://prodstack-zone-1.clouds.archive.ubuntu.com xenial/multiverse Sources [178 kB]
Get:6 http://prodstack-zone-1.clouds.archive.ubuntu.com xenial/main amd64 Packages [1,446 kB]
Get:7 http://prodstack-zone-1.clouds.archive.ubuntu.com xenial/restricted amd64 Packages [15.8 kB]
Get:8 http://prodstack-zone-1.clouds.archive.ubuntu.com xenial/universe amd64 Packages [6,983 kB]
Get:9 http://prodstack-zone-1.clouds.archive.ubuntu.com xenial/multiverse amd64 Packages [138 kB]
Get:10 http://prodstack-zone-1.clouds.archive.ubuntu.com xenial/main Translation-en [844 kB]
Get:11 http://prodstack-zone-1.clouds.archive.ubuntu.com xenial/multiverse Translation-en [108 kB]
Get:12 http://prodstack-zone-1.clouds.archive.ubuntu.com xenial/restricted Translation-en [4,302 B]
Get:13 http://prodstack-zone-1.clouds.archive.ubuntu.com xenial/universe Translation-en [4,716 kB]
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com xenial-updates/main Sources
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com xenial-updates/restricted Sources
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com xenial-updates/universe Sources
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com xenial-updates/multiverse Sources
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com xenial-updates/main amd64 Packages
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com xenial-updates/restricted amd64 Packages
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com xenial-updates/universe amd64 Packages
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com xenial-updates/multiverse amd64 Packages
Hit http://prodstack-zone-1.clouds.archive.ubuntu.com xenial-updates/main Translation-en
Hit ht...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/provisioningserver/network.py'
2--- src/provisioningserver/network.py 2015-10-23 21:26:12 +0000
3+++ src/provisioningserver/network.py 2015-11-25 20:22:18 +0000
4@@ -163,6 +163,7 @@
5 for network in networks
6 if 'interface' in network and
7 (network['interface'].startswith('eth') or
8+ network['interface'].startswith('en') or
9 network['interface'].startswith('em') or
10 network['interface'].startswith('vlan') or
11 network['interface'].startswith('bond'))
12
13=== modified file 'src/provisioningserver/utils/ipaddr.py'
14--- src/provisioningserver/utils/ipaddr.py 2015-10-23 10:28:17 +0000
15+++ src/provisioningserver/utils/ipaddr.py 2015-11-25 20:22:18 +0000
16@@ -281,11 +281,8 @@
17 return 'ethernet.bond'
18 if os.path.isfile('%s/%s' % (proc_net_vlan, ifname)):
19 return 'ethernet.vlan'
20- module_name_link = os.path.join(sys_path, 'device', 'driver', 'module')
21- if not os.path.islink(module_name_link):
22- return 'ethernet'
23- module_name = os.readlink(module_name_link).split('/')[-1]
24- if module_name:
25+ device_path = os.path.join(sys_path, 'device')
26+ if os.path.islink(device_path):
27 device_80211 = os.path.join(sys_path, 'device', 'ieee80211')
28 if os.path.isdir(device_80211):
29 return 'ethernet.wireless'
30
31=== modified file 'src/provisioningserver/utils/tests/test_ipaddr.py'
32--- src/provisioningserver/utils/tests/test_ipaddr.py 2015-10-23 10:28:17 +0000
33+++ src/provisioningserver/utils/tests/test_ipaddr.py 2015-11-25 20:22:18 +0000
34@@ -349,13 +349,9 @@
35 f.write(b"%s\n" % ' '.join(bonded_interfaces).encode('utf-8'))
36 f.close()
37 if is_physical or is_wireless:
38- os.mkdir(os.path.join(ifdir, 'device'))
39- os.mkdir(os.path.join(ifdir, 'device', 'driver'))
40- # Note: the symlink here doesn't actually need to resolve
41- # to a real file.
42- os.symlink(
43- os.path.join('..', 'driver_module_name'),
44- os.path.join(ifdir, 'device', 'driver', 'module'))
45+ device_real = os.path.join(ifdir, 'device.real')
46+ os.mkdir(device_real)
47+ os.symlink(device_real, os.path.join(ifdir, 'device'))
48 if is_wireless:
49 os.mkdir(os.path.join(ifdir, 'device', 'ieee80211'))
50
51@@ -480,6 +476,10 @@
52
53 def test__filters_based_on_name_by_default(self):
54 input_networks = [
55+ {"interface": "eno1"},
56+ {"interface": "ens3"},
57+ {"interface": "enp0s25"},
58+ {"interface": "enx78e7d1ea46da"},
59 {"interface": "em0"},
60 {"interface": "eth0"},
61 {"interface": "vlan0"},
62@@ -490,6 +490,10 @@
63 ]
64 actual_networks = filter_and_annotate_networks(input_networks)
65 expected_networks = [
66+ {"interface": "eno1"},
67+ {"interface": "ens3"},
68+ {"interface": "enp0s25"},
69+ {"interface": "enx78e7d1ea46da"},
70 {"interface": "em0"},
71 {"interface": "eth0"},
72 {"interface": "vlan0"},
73@@ -499,6 +503,10 @@
74
75 def test__filters_and_annotates_based_on_json_data_if_available(self):
76 input_networks = [
77+ {"interface": "eno1"},
78+ {"interface": "ens3"},
79+ {"interface": "enp0s25"},
80+ {"interface": "enx78e7d1ea46da"},
81 {"interface": "em0"},
82 {"interface": "eth0"},
83 {"interface": "vlan0"},
84@@ -521,7 +529,7 @@
85 "bridged_interfaces": ["avian0"]},
86 "br3": {"type": "ethernet.bridge"},
87 "wlan0": {"type": "ethernet.bond",
88- "bonded_interfaces": ["em0", "eth0"]}
89+ "bonded_interfaces": ["eno1", "eth0"]}
90 }
91 actual_networks = filter_and_annotate_networks(
92 input_networks, json.dumps(input_json))
93@@ -533,12 +541,16 @@
94 "bridged_interfaces": "avian0"},
95 {"interface": "br3", 'type': "ethernet.bridge"},
96 {"interface": "wlan0", 'type': "ethernet.bond",
97- "bonded_interfaces": "em0 eth0"},
98+ "bonded_interfaces": "eno1 eth0"},
99 ]
100 self.assertThat(actual_networks, Equals(expected_networks))
101
102 def test__falls_back_to_names_if_no_interfaces_found(self):
103 input_networks = [
104+ {"interface": "eno1"},
105+ {"interface": "ens3"},
106+ {"interface": "enp0s25"},
107+ {"interface": "enx78e7d1ea46da"},
108 {"interface": "em0"},
109 {"interface": "eth0"},
110 {"interface": "vlan0"},
111@@ -552,6 +564,10 @@
112 actual_networks = filter_and_annotate_networks(
113 input_networks, json.dumps(input_json))
114 expected_networks = [
115+ {"interface": "eno1"},
116+ {"interface": "ens3"},
117+ {"interface": "enp0s25"},
118+ {"interface": "enx78e7d1ea46da"},
119 {"interface": "em0"},
120 {"interface": "eth0"},
121 {"interface": "vlan0"},