Merge lp:~hopem/charm-helpers/allow-list-nics-return-all into lp:charm-helpers
- allow-list-nics-return-all
- Merge into devel
Proposed by
Edward Hope-Morley
Status: | Superseded |
---|---|
Proposed branch: | lp:~hopem/charm-helpers/allow-list-nics-return-all |
Merge into: | lp:charm-helpers |
Diff against target: |
343 lines (+132/-45) 6 files modified
charmhelpers/contrib/openstack/context.py (+17/-10) charmhelpers/contrib/openstack/neutron.py (+29/-16) charmhelpers/core/host.py (+45/-11) tests/contrib/openstack/test_neutron_utils.py (+3/-3) tests/contrib/openstack/test_os_contexts.py (+7/-2) tests/core/test_host.py (+31/-3) |
To merge this branch: | bzr merge lp:~hopem/charm-helpers/allow-list-nics-return-all |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Liam Young (community) | Needs Fixing | ||
Review via email:
|
This proposal has been superseded by a proposal from 2015-08-18.
Commit message
Description of the change
To post a comment you must log in.
- 432. By Edward Hope-Morley
-
[hopem,r=]
Add support to core.host.
list_nics( ) to allow for listing
all nics i.e. unfiltered. Ensure that neutron resolve_ports
only resolves physical interfaces. - 433. By Edward Hope-Morley
-
Add support for identiying bonded nics and resolving
their master. - 434. By Edward Hope-Morley
-
ensure master is bond
- 435. By Edward Hope-Morley
-
added multimac unit test
- 436. By Edward Hope-Morley
-
more unit test
- 437. By Edward Hope-Morley
-
*fix* py3 unit test error
- 438. By Edward Hope-Morley
-
fix unit test
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'charmhelpers/contrib/openstack/context.py' | |||
2 | --- charmhelpers/contrib/openstack/context.py 2015-07-29 14:21:45 +0000 | |||
3 | +++ charmhelpers/contrib/openstack/context.py 2015-08-18 11:36:40 +0000 | |||
4 | @@ -50,6 +50,7 @@ | |||
5 | 50 | from charmhelpers.core.strutils import bool_from_string | 50 | from charmhelpers.core.strutils import bool_from_string |
6 | 51 | 51 | ||
7 | 52 | from charmhelpers.core.host import ( | 52 | from charmhelpers.core.host import ( |
8 | 53 | is_phy_iface, | ||
9 | 53 | list_nics, | 54 | list_nics, |
10 | 54 | get_nic_hwaddr, | 55 | get_nic_hwaddr, |
11 | 55 | mkdir, | 56 | mkdir, |
12 | @@ -923,7 +924,6 @@ | |||
13 | 923 | 924 | ||
14 | 924 | 925 | ||
15 | 925 | class NeutronPortContext(OSContextGenerator): | 926 | class NeutronPortContext(OSContextGenerator): |
16 | 926 | NIC_PREFIXES = ['eth', 'bond'] | ||
17 | 927 | 927 | ||
18 | 928 | def resolve_ports(self, ports): | 928 | def resolve_ports(self, ports): |
19 | 929 | """Resolve NICs not yet bound to bridge(s) | 929 | """Resolve NICs not yet bound to bridge(s) |
20 | @@ -935,12 +935,14 @@ | |||
21 | 935 | 935 | ||
22 | 936 | hwaddr_to_nic = {} | 936 | hwaddr_to_nic = {} |
23 | 937 | hwaddr_to_ip = {} | 937 | hwaddr_to_ip = {} |
30 | 938 | for nic in list_nics(self.NIC_PREFIXES): | 938 | for nic in list_nics(): |
31 | 939 | hwaddr = get_nic_hwaddr(nic) | 939 | # Ignore virtual interfaces |
32 | 940 | hwaddr_to_nic[hwaddr] = nic | 940 | if is_phy_iface(nic): |
33 | 941 | addresses = get_ipv4_addr(nic, fatal=False) | 941 | hwaddr = get_nic_hwaddr(nic) |
34 | 942 | addresses += get_ipv6_addr(iface=nic, fatal=False) | 942 | hwaddr_to_nic[hwaddr] = nic |
35 | 943 | hwaddr_to_ip[hwaddr] = addresses | 943 | addresses = get_ipv4_addr(nic, fatal=False) |
36 | 944 | addresses += get_ipv6_addr(iface=nic, fatal=False) | ||
37 | 945 | hwaddr_to_ip[hwaddr] = addresses | ||
38 | 944 | 946 | ||
39 | 945 | resolved = [] | 947 | resolved = [] |
40 | 946 | mac_regex = re.compile(r'([0-9A-F]{2}[:-]){5}([0-9A-F]{2})', re.I) | 948 | mac_regex = re.compile(r'([0-9A-F]{2}[:-]){5}([0-9A-F]{2})', re.I) |
41 | @@ -961,7 +963,8 @@ | |||
42 | 961 | # trust it to be the real external network). | 963 | # trust it to be the real external network). |
43 | 962 | resolved.append(entry) | 964 | resolved.append(entry) |
44 | 963 | 965 | ||
46 | 964 | return resolved | 966 | # Ensure no duplicates |
47 | 967 | return list(set(resolved)) | ||
48 | 965 | 968 | ||
49 | 966 | 969 | ||
50 | 967 | class OSConfigFlagContext(OSContextGenerator): | 970 | class OSConfigFlagContext(OSContextGenerator): |
51 | @@ -1280,15 +1283,19 @@ | |||
52 | 1280 | def __call__(self): | 1283 | def __call__(self): |
53 | 1281 | ports = config('data-port') | 1284 | ports = config('data-port') |
54 | 1282 | if ports: | 1285 | if ports: |
55 | 1286 | # Map of {port/mac:bridge} | ||
56 | 1283 | portmap = parse_data_port_mappings(ports) | 1287 | portmap = parse_data_port_mappings(ports) |
58 | 1284 | ports = portmap.values() | 1288 | ports = portmap.keys() |
59 | 1289 | # Resolve provided ports or mac addresses and filter out those | ||
60 | 1290 | # already attached to a bridge. | ||
61 | 1285 | resolved = self.resolve_ports(ports) | 1291 | resolved = self.resolve_ports(ports) |
62 | 1292 | # FIXME: is this necessary? | ||
63 | 1286 | normalized = {get_nic_hwaddr(port): port for port in resolved | 1293 | normalized = {get_nic_hwaddr(port): port for port in resolved |
64 | 1287 | if port not in ports} | 1294 | if port not in ports} |
65 | 1288 | normalized.update({port: port for port in resolved | 1295 | normalized.update({port: port for port in resolved |
66 | 1289 | if port in ports}) | 1296 | if port in ports}) |
67 | 1290 | if resolved: | 1297 | if resolved: |
69 | 1291 | return {bridge: normalized[port] for bridge, port in | 1298 | return {bridge: normalized[port] for port, bridge in |
70 | 1292 | six.iteritems(portmap) if port in normalized.keys()} | 1299 | six.iteritems(portmap) if port in normalized.keys()} |
71 | 1293 | 1300 | ||
72 | 1294 | return None | 1301 | return None |
73 | 1295 | 1302 | ||
74 | === modified file 'charmhelpers/contrib/openstack/neutron.py' | |||
75 | --- charmhelpers/contrib/openstack/neutron.py 2015-06-10 11:17:45 +0000 | |||
76 | +++ charmhelpers/contrib/openstack/neutron.py 2015-08-18 11:36:40 +0000 | |||
77 | @@ -255,17 +255,30 @@ | |||
78 | 255 | return 'neutron' | 255 | return 'neutron' |
79 | 256 | 256 | ||
80 | 257 | 257 | ||
82 | 258 | def parse_mappings(mappings): | 258 | def parse_mappings(mappings, key_rvalue=False): |
83 | 259 | """By default mappings are lvalue keyed. | ||
84 | 260 | |||
85 | 261 | If key_rvalue is True, the mapping will be reversed to allow multiple | ||
86 | 262 | configs for the same lvalue. | ||
87 | 263 | """ | ||
88 | 259 | parsed = {} | 264 | parsed = {} |
89 | 260 | if mappings: | 265 | if mappings: |
90 | 261 | mappings = mappings.split() | 266 | mappings = mappings.split() |
91 | 262 | for m in mappings: | 267 | for m in mappings: |
92 | 263 | p = m.partition(':') | 268 | p = m.partition(':') |
96 | 264 | key = p[0].strip() | 269 | |
97 | 265 | if p[1]: | 270 | if key_rvalue: |
98 | 266 | parsed[key] = p[2].strip() | 271 | key_index = 2 |
99 | 272 | val_index = 0 | ||
100 | 273 | # if there is no rvalue skip to next | ||
101 | 274 | if not p[1]: | ||
102 | 275 | continue | ||
103 | 267 | else: | 276 | else: |
105 | 268 | parsed[key] = '' | 277 | key_index = 0 |
106 | 278 | val_index = 2 | ||
107 | 279 | |||
108 | 280 | key = p[key_index].strip() | ||
109 | 281 | parsed[key] = p[val_index].strip() | ||
110 | 269 | 282 | ||
111 | 270 | return parsed | 283 | return parsed |
112 | 271 | 284 | ||
113 | @@ -283,25 +296,25 @@ | |||
114 | 283 | def parse_data_port_mappings(mappings, default_bridge='br-data'): | 296 | def parse_data_port_mappings(mappings, default_bridge='br-data'): |
115 | 284 | """Parse data port mappings. | 297 | """Parse data port mappings. |
116 | 285 | 298 | ||
118 | 286 | Mappings must be a space-delimited list of bridge:port mappings. | 299 | Mappings must be a space-delimited list of port:bridge mappings. |
119 | 287 | 300 | ||
121 | 288 | Returns dict of the form {bridge:port}. | 301 | Returns dict of the form {port:bridge} where port may be an mac address or |
122 | 302 | interface name. | ||
123 | 289 | """ | 303 | """ |
125 | 290 | _mappings = parse_mappings(mappings) | 304 | |
126 | 305 | # NOTE(dosaboy): we use rvalue for key to allow multiple values to be | ||
127 | 306 | # proposed for <port> since it may be a mac address which will differ | ||
128 | 307 | # across units this allowing first-known-good to be chosen. | ||
129 | 308 | _mappings = parse_mappings(mappings, key_rvalue=True) | ||
130 | 291 | if not _mappings or list(_mappings.values()) == ['']: | 309 | if not _mappings or list(_mappings.values()) == ['']: |
131 | 292 | if not mappings: | 310 | if not mappings: |
132 | 293 | return {} | 311 | return {} |
133 | 294 | 312 | ||
134 | 295 | # For backwards-compatibility we need to support port-only provided in | 313 | # For backwards-compatibility we need to support port-only provided in |
135 | 296 | # config. | 314 | # config. |
144 | 297 | _mappings = {default_bridge: mappings.split()[0]} | 315 | _mappings = {mappings.split()[0]: default_bridge} |
145 | 298 | 316 | ||
146 | 299 | bridges = _mappings.keys() | 317 | ports = _mappings.keys() |
139 | 300 | ports = _mappings.values() | ||
140 | 301 | if len(set(bridges)) != len(bridges): | ||
141 | 302 | raise Exception("It is not allowed to have more than one port " | ||
142 | 303 | "configured on the same bridge") | ||
143 | 304 | |||
147 | 305 | if len(set(ports)) != len(ports): | 318 | if len(set(ports)) != len(ports): |
148 | 306 | raise Exception("It is not allowed to have the same port configured " | 319 | raise Exception("It is not allowed to have the same port configured " |
149 | 307 | "on more than one bridge") | 320 | "on more than one bridge") |
150 | 308 | 321 | ||
151 | === modified file 'charmhelpers/core/host.py' | |||
152 | --- charmhelpers/core/host.py 2015-08-17 11:15:38 +0000 | |||
153 | +++ charmhelpers/core/host.py 2015-08-18 11:36:40 +0000 | |||
154 | @@ -417,25 +417,59 @@ | |||
155 | 417 | return(''.join(random_chars)) | 417 | return(''.join(random_chars)) |
156 | 418 | 418 | ||
157 | 419 | 419 | ||
159 | 420 | def list_nics(nic_type): | 420 | def is_phy_iface(interface): |
160 | 421 | """Returns True if interface is not virtual, otherwise False.""" | ||
161 | 422 | if interface: | ||
162 | 423 | sys_net = '/sys/class/net' | ||
163 | 424 | if os.path.isdir(sys_net): | ||
164 | 425 | for iface in glob.glob(os.path.join(sys_net, '*')): | ||
165 | 426 | if '/virtual/' in os.path.realpath(iface): | ||
166 | 427 | continue | ||
167 | 428 | |||
168 | 429 | if interface == os.path.basename(iface): | ||
169 | 430 | return True | ||
170 | 431 | |||
171 | 432 | return False | ||
172 | 433 | |||
173 | 434 | |||
174 | 435 | def list_nics(nic_type=None): | ||
175 | 421 | '''Return a list of nics of given type(s)''' | 436 | '''Return a list of nics of given type(s)''' |
176 | 422 | if isinstance(nic_type, six.string_types): | 437 | if isinstance(nic_type, six.string_types): |
177 | 423 | int_types = [nic_type] | 438 | int_types = [nic_type] |
178 | 424 | else: | 439 | else: |
179 | 425 | int_types = nic_type | 440 | int_types = nic_type |
180 | 441 | |||
181 | 426 | interfaces = [] | 442 | interfaces = [] |
184 | 427 | for int_type in int_types: | 443 | if nic_type: |
185 | 428 | cmd = ['ip', 'addr', 'show', 'label', int_type + '*'] | 444 | for int_type in int_types: |
186 | 445 | cmd = ['ip', 'addr', 'show', 'label', int_type + '*'] | ||
187 | 446 | ip_output = subprocess.check_output(cmd).decode('UTF-8') | ||
188 | 447 | ip_output = ip_output.split('\n') | ||
189 | 448 | ip_output = (line for line in ip_output if line) | ||
190 | 449 | for line in ip_output: | ||
191 | 450 | if line.split()[1].startswith(int_type): | ||
192 | 451 | matched = re.search('.*: (' + int_type + | ||
193 | 452 | r'[0-9]+\.[0-9]+)@.*', line) | ||
194 | 453 | if matched: | ||
195 | 454 | iface = matched.groups()[0] | ||
196 | 455 | else: | ||
197 | 456 | iface = line.split()[1].replace(":", "") | ||
198 | 457 | |||
199 | 458 | if iface not in interfaces: | ||
200 | 459 | interfaces.append(iface) | ||
201 | 460 | else: | ||
202 | 461 | cmd = ['ip', 'a'] | ||
203 | 429 | ip_output = subprocess.check_output(cmd).decode('UTF-8').split('\n') | 462 | ip_output = subprocess.check_output(cmd).decode('UTF-8').split('\n') |
205 | 430 | ip_output = (line for line in ip_output if line) | 463 | ip_output = (line.strip() for line in ip_output if line) |
206 | 464 | |||
207 | 465 | key = re.compile('^[0-9]+:\s+(.+):') | ||
208 | 431 | for line in ip_output: | 466 | for line in ip_output: |
216 | 432 | if line.split()[1].startswith(int_type): | 467 | matched = re.search(key, line) |
217 | 433 | matched = re.search('.*: (' + int_type + r'[0-9]+\.[0-9]+)@.*', line) | 468 | if matched: |
218 | 434 | if matched: | 469 | iface = matched.group(1) |
219 | 435 | interface = matched.groups()[0] | 470 | iface = iface.partition("@")[0] |
220 | 436 | else: | 471 | if iface not in interfaces: |
221 | 437 | interface = line.split()[1].replace(":", "") | 472 | interfaces.append(iface) |
215 | 438 | interfaces.append(interface) | ||
222 | 439 | 473 | ||
223 | 440 | return interfaces | 474 | return interfaces |
224 | 441 | 475 | ||
225 | 442 | 476 | ||
226 | === modified file 'tests/contrib/openstack/test_neutron_utils.py' | |||
227 | --- tests/contrib/openstack/test_neutron_utils.py 2015-05-02 22:27:26 +0000 | |||
228 | +++ tests/contrib/openstack/test_neutron_utils.py 2015-08-18 11:36:40 +0000 | |||
229 | @@ -181,13 +181,13 @@ | |||
230 | 181 | ret = neutron.parse_data_port_mappings(None) | 181 | ret = neutron.parse_data_port_mappings(None) |
231 | 182 | self.assertEqual(ret, {}) | 182 | self.assertEqual(ret, {}) |
232 | 183 | ret = neutron.parse_data_port_mappings('br0:eth0') | 183 | ret = neutron.parse_data_port_mappings('br0:eth0') |
234 | 184 | self.assertEqual(ret, {'br0': 'eth0'}) | 184 | self.assertEqual(ret, {'eth0': 'br0'}) |
235 | 185 | # Back-compat test | 185 | # Back-compat test |
236 | 186 | ret = neutron.parse_data_port_mappings('eth0', default_bridge='br0') | 186 | ret = neutron.parse_data_port_mappings('eth0', default_bridge='br0') |
238 | 187 | self.assertEqual(ret, {'br0': 'eth0'}) | 187 | self.assertEqual(ret, {'eth0': 'br0'}) |
239 | 188 | # Multiple mappings | 188 | # Multiple mappings |
240 | 189 | ret = neutron.parse_data_port_mappings('br0:eth0 br1:eth1') | 189 | ret = neutron.parse_data_port_mappings('br0:eth0 br1:eth1') |
242 | 190 | self.assertEqual(ret, {'br0': 'eth0', 'br1': 'eth1'}) | 190 | self.assertEqual(ret, {'eth0': 'br0', 'eth1': 'br1'}) |
243 | 191 | 191 | ||
244 | 192 | def test_parse_vlan_range_mappings(self): | 192 | def test_parse_vlan_range_mappings(self): |
245 | 193 | ret = neutron.parse_vlan_range_mappings(None) | 193 | ret = neutron.parse_vlan_range_mappings(None) |
246 | 194 | 194 | ||
247 | === modified file 'tests/contrib/openstack/test_os_contexts.py' | |||
248 | --- tests/contrib/openstack/test_os_contexts.py 2015-07-29 14:21:45 +0000 | |||
249 | +++ tests/contrib/openstack/test_os_contexts.py 2015-08-18 11:36:40 +0000 | |||
250 | @@ -2425,6 +2425,8 @@ | |||
251 | 2425 | self.assertEquals(context.ExternalPortContext()(), | 2425 | self.assertEquals(context.ExternalPortContext()(), |
252 | 2426 | {'ext_port': 'eth1010'}) | 2426 | {'ext_port': 'eth1010'}) |
253 | 2427 | 2427 | ||
254 | 2428 | @patch('charmhelpers.contrib.openstack.context.is_phy_iface', | ||
255 | 2429 | lambda arg: True) | ||
256 | 2428 | @patch('charmhelpers.contrib.openstack.context.get_nic_hwaddr') | 2430 | @patch('charmhelpers.contrib.openstack.context.get_nic_hwaddr') |
257 | 2429 | @patch('charmhelpers.contrib.openstack.context.list_nics') | 2431 | @patch('charmhelpers.contrib.openstack.context.list_nics') |
258 | 2430 | @patch('charmhelpers.contrib.openstack.context.get_ipv6_addr') | 2432 | @patch('charmhelpers.contrib.openstack.context.get_ipv6_addr') |
259 | @@ -2452,6 +2454,8 @@ | |||
260 | 2452 | 2454 | ||
261 | 2453 | self.assertEquals(context.ExternalPortContext()(), {}) | 2455 | self.assertEquals(context.ExternalPortContext()(), {}) |
262 | 2454 | 2456 | ||
263 | 2457 | @patch('charmhelpers.contrib.openstack.context.is_phy_iface', | ||
264 | 2458 | lambda arg: True) | ||
265 | 2455 | @patch('charmhelpers.contrib.openstack.context.get_nic_hwaddr') | 2459 | @patch('charmhelpers.contrib.openstack.context.get_nic_hwaddr') |
266 | 2456 | @patch('charmhelpers.contrib.openstack.context.list_nics') | 2460 | @patch('charmhelpers.contrib.openstack.context.list_nics') |
267 | 2457 | @patch('charmhelpers.contrib.openstack.context.get_ipv6_addr') | 2461 | @patch('charmhelpers.contrib.openstack.context.get_ipv6_addr') |
268 | @@ -2484,8 +2488,9 @@ | |||
269 | 2484 | 'resolve_ports') | 2488 | 'resolve_ports') |
270 | 2485 | def test_data_port_eth(self, mock_resolve): | 2489 | def test_data_port_eth(self, mock_resolve): |
271 | 2486 | self.config.side_effect = fake_config({'data-port': | 2490 | self.config.side_effect = fake_config({'data-port': |
274 | 2487 | 'phybr1:eth1010'}) | 2491 | 'phybr1:eth1010 ' |
275 | 2488 | mock_resolve.side_effect = lambda ports: ports | 2492 | 'phybr1:eth1011'}) |
276 | 2493 | mock_resolve.side_effect = lambda ports: ['eth1010'] | ||
277 | 2489 | self.assertEquals(context.DataPortContext()(), | 2494 | self.assertEquals(context.DataPortContext()(), |
278 | 2490 | {'phybr1': 'eth1010'}) | 2495 | {'phybr1': 'eth1010'}) |
279 | 2491 | 2496 | ||
280 | 2492 | 2497 | ||
281 | === modified file 'tests/core/test_host.py' | |||
282 | --- tests/core/test_host.py 2015-08-17 11:15:38 +0000 | |||
283 | +++ tests/core/test_host.py 2015-08-18 11:36:40 +0000 | |||
284 | @@ -35,6 +35,11 @@ | |||
285 | 35 | link/ether e4:11:5b:ab:a7:3c brd ff:ff:ff:ff:ff:ff | 35 | link/ether e4:11:5b:ab:a7:3c brd ff:ff:ff:ff:ff:ff |
286 | 36 | """ | 36 | """ |
287 | 37 | 37 | ||
288 | 38 | IP_LINE_ETH100 = b""" | ||
289 | 39 | 2: eth100: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc mq master bond0 state UP qlen 1000 | ||
290 | 40 | link/ether e4:11:5b:ab:a7:3d brd ff:ff:ff:ff:ff:ff | ||
291 | 41 | """ | ||
292 | 42 | |||
293 | 38 | IP_LINE_ETH0_VLAN = b""" | 43 | IP_LINE_ETH0_VLAN = b""" |
294 | 39 | 6: eth0.10@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default | 44 | 6: eth0.10@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default |
295 | 40 | link/ether 08:00:27:16:b9:5f brd ff:ff:ff:ff:ff:ff | 45 | link/ether 08:00:27:16:b9:5f brd ff:ff:ff:ff:ff:ff |
296 | @@ -47,7 +52,7 @@ | |||
297 | 47 | 52 | ||
298 | 48 | IP_LINE_HWADDR = b"""2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000\ link/ether e4:11:5b:ab:a7:3c brd ff:ff:ff:ff:ff:ff""" | 53 | IP_LINE_HWADDR = b"""2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000\ link/ether e4:11:5b:ab:a7:3c brd ff:ff:ff:ff:ff:ff""" |
299 | 49 | 54 | ||
301 | 50 | IP_LINES = IP_LINE_ETH0 + IP_LINE_ETH1 + IP_LINE_ETH0_VLAN | 55 | IP_LINES = IP_LINE_ETH0 + IP_LINE_ETH1 + IP_LINE_ETH0_VLAN + IP_LINE_ETH100 |
302 | 51 | 56 | ||
303 | 52 | IP_LINE_BONDS = b""" | 57 | IP_LINE_BONDS = b""" |
304 | 53 | 6: bond0.10@bond0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default | 58 | 6: bond0.10@bond0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default |
305 | @@ -962,13 +967,36 @@ | |||
306 | 962 | pw2 = host.pwgen(10) | 967 | pw2 = host.pwgen(10) |
307 | 963 | self.assertNotEqual(pw, pw2, 'Duplicated password') | 968 | self.assertNotEqual(pw, pw2, 'Duplicated password') |
308 | 964 | 969 | ||
309 | 970 | @patch.object(host, 'glob') | ||
310 | 971 | @patch('os.path.realpath') | ||
311 | 972 | @patch('os.path.isdir') | ||
312 | 973 | def test_is_phy_iface(self, mock_isdir, mock_realpath, mock_glob): | ||
313 | 974 | mock_isdir.return_value = True | ||
314 | 975 | mock_glob.glob.return_value = ['/sys/class/net/eth0', | ||
315 | 976 | '/sys/class/net/veth0'] | ||
316 | 977 | |||
317 | 978 | def fake_realpath(soft): | ||
318 | 979 | if soft.endswith('/eth0'): | ||
319 | 980 | hard = \ | ||
320 | 981 | '/sys/devices/pci0000:00/0000:00:1c.4/0000:02:00.1/net/eth0' | ||
321 | 982 | else: | ||
322 | 983 | hard = '/sys/devices/virtual/net/veth0' | ||
323 | 984 | |||
324 | 985 | return hard | ||
325 | 986 | |||
326 | 987 | mock_realpath.side_effect = fake_realpath | ||
327 | 988 | self.assertTrue(host.is_phy_iface('eth0')) | ||
328 | 989 | self.assertFalse(host.is_phy_iface('veth0')) | ||
329 | 990 | |||
330 | 965 | @patch('subprocess.check_output') | 991 | @patch('subprocess.check_output') |
331 | 966 | def test_list_nics(self, check_output): | 992 | def test_list_nics(self, check_output): |
332 | 967 | check_output.return_value = IP_LINES | 993 | check_output.return_value = IP_LINES |
333 | 994 | nics = host.list_nics() | ||
334 | 995 | self.assertEqual(nics, ['eth0', 'eth1', 'eth0.10', 'eth100']) | ||
335 | 968 | nics = host.list_nics('eth') | 996 | nics = host.list_nics('eth') |
337 | 969 | self.assertEqual(nics, ['eth0', 'eth1', 'eth0.10']) | 997 | self.assertEqual(nics, ['eth0', 'eth1', 'eth0.10', 'eth100']) |
338 | 970 | nics = host.list_nics(['eth']) | 998 | nics = host.list_nics(['eth']) |
340 | 971 | self.assertEqual(nics, ['eth0', 'eth1', 'eth0.10']) | 999 | self.assertEqual(nics, ['eth0', 'eth1', 'eth0.10', 'eth100']) |
341 | 972 | 1000 | ||
342 | 973 | @patch('subprocess.check_output') | 1001 | @patch('subprocess.check_output') |
343 | 974 | def test_list_nics_with_bonds(self, check_output): | 1002 | def test_list_nics_with_bonds(self, check_output): |
Please could you update the unit tests so that the macs of IP_LINE_ETH0 and IP_LINE_ETH0_VLAN match and add a test for list_nics(['eth'], include_ vlans=False) ?
As a nitpick I think it's cleaner parse the output of ip when using '-o' so that all entries are on one line but that's how it was before so I won't block on it.