Skip to content

Commit fb3301d

Browse files
costasdphilpep
authored andcommitted
iproute2: convert to Module from InstanceModule
1 parent 09d4cb0 commit fb3301d

File tree

3 files changed

+245
-24
lines changed

3 files changed

+245
-24
lines changed

doc/source/modules.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ IProute2
186186
.. autoclass:: testinfra.modules.iproute2.IProute2
187187
:members:
188188
:undoc-members:
189-
189+
:exclude-members: get_module_class
190190

191191
Iptables
192192
~~~~~~~~~

test/test_modules.py

+4
Original file line numberDiff line numberDiff line change
@@ -739,18 +739,21 @@ def test_iproute2_netns(host):
739739
assert len(namespaces) == 1
740740
assert namespaces[0].get("name") == "test"
741741

742+
742743
def test_iproute2_bridge_vlan(host):
743744
assert host.iproute2.bridge_exists
744745

745746
vlans = host.iproute2.bridge_vlan()
746747
assert len(vlans) == 0
747748

749+
748750
def test_iproute2_bridge_fdb(host):
749751
assert host.iproute2.bridge_exists
750752

751753
fdb = host.iproute2.bridge_fdb()
752754
assert len(fdb) > 0
753755

756+
754757
def test_iproute2_bridge_mdb(host):
755758
assert host.iproute2.bridge_exists
756759

@@ -759,6 +762,7 @@ def test_iproute2_bridge_mdb(host):
759762
assert len(mdb[0].get("mdb")) == 0
760763
assert len(mdb[0].get("router")) == 0
761764

765+
762766
def test_iproute2_bridge_link(host):
763767
assert host.iproute2.bridge_exists
764768

testinfra/modules/iproute2.py

+240-23
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
import functools
1414
import json
1515

16-
from testinfra.modules.base import InstanceModule
16+
from testinfra.modules.base import Module
1717

1818

19-
class IProute2(InstanceModule):
20-
"""Test network configuration via iproute2 commands
19+
class IProute2(Module):
20+
"""Tests network configuration via iproute2 commands
2121
2222
Currently supported:
2323
@@ -33,12 +33,14 @@ class IProute2(InstanceModule):
3333
* bridge fdb
3434
* bridge mdb
3535
36-
Optional module-level arguments can also be provided to contro; execution:
36+
Optional module-level arguments can also be provided to control execution:
37+
38+
* **family**: force iproute2 tools to use a specific protocol family
3739
38-
* family: force iproute2 tools to use a specific protocol family
3940
>>> host.iproute2(family="inet").addresses()
4041
41-
* namespace: execute iproute2 tools inside the provided namespace
42+
* **namespace**: execute iproute2 tools inside the provided namespace
43+
4244
>>> host.iproute2(namespace="test").addresses()
4345
4446
"""
@@ -51,6 +53,221 @@ def __init__(self, family=None, namespace=None):
5153
def __repr__(self):
5254
return "<ip>"
5355

56+
@classmethod
57+
def get_module_class(cls, host):
58+
if host.system_info.type == "linux":
59+
return LinuxIProute2
60+
raise NotImplementedError
61+
62+
@property
63+
def exists(self):
64+
"""Returns True if ip -V succeeds
65+
66+
>>> host.iproute2.exists
67+
True
68+
69+
"""
70+
71+
@property
72+
def bridge_exists(self):
73+
"""Returns True if bridge -V succeeds
74+
75+
>>> host.iproute2.bridge_exists
76+
True
77+
78+
"""
79+
80+
def addresses(self, address=None, ifname=None, local=None):
81+
"""Returns the addresses associated with interfaces
82+
83+
>>> host.iproute2.addresses()
84+
[{'ifindex': 1,
85+
'ifname': 'lo',
86+
'flags': ['LOOPBACK', 'UP', 'LOWER_UP'],
87+
'mtu': 65536,
88+
'qdisc': 'noqueue',
89+
'operstate': 'UNKNOWN',
90+
'group': 'default',
91+
'txqlen': 1000,
92+
'link_type': 'loopback',
93+
'address': '00:00:00:00:00:00',
94+
'broadcast': '00:00:00:00:00:00',
95+
'addr_info': [{'family': 'inet',
96+
'local': '127.0.0.1',
97+
'prefixlen': 8,
98+
'scope': 'host',
99+
'label': 'lo',
100+
'valid_life_time': 4294967295,
101+
'preferred_life_time': 4294967295},
102+
{'family': 'inet6',
103+
'local': '::1',
104+
'prefixlen': 128,
105+
'scope': 'host',
106+
'noprefixroute': True,
107+
'valid_life_time': 4294967295,
108+
'preferred_life_time': 4294967295}]}]
109+
110+
Optionally, results can be filtered with the following selectors:
111+
112+
* address
113+
* ifname
114+
* local
115+
116+
"""
117+
118+
def links(self):
119+
"""Returns links and their state.
120+
121+
>>> host.iproute2.links()
122+
[{'ifindex': 1,
123+
'ifname': 'lo',
124+
'flags': ['LOOPBACK', 'UP', 'LOWER_UP'],
125+
'mtu': 65536,
126+
'qdisc': 'noqueue',
127+
'operstate': 'UNKNOWN',
128+
'linkmode': 'DEFAULT',
129+
'group': 'default',
130+
'txqlen': 1000,
131+
'link_type': 'loopback',
132+
'address': '00:00:00:00:00:00',
133+
'broadcast': '00:00:00:00:00:00'}]
134+
135+
"""
136+
137+
def routes(
138+
self, table="all", device=None, scope=None, proto=None, src=None, metric=None
139+
):
140+
"""Returns the routes installed in *all* routing tables.
141+
142+
>>> host.iproute2.routes()
143+
[{'dst': '169.254.0.0/16',
144+
'dev': 'wlp4s0',
145+
'scope': 'link',
146+
'metric': 1000,
147+
'flags': []},
148+
{'type': 'multicast',
149+
'dst': 'ff00::/8',
150+
'dev': 'wlp4s0',
151+
'table': 'local',
152+
'protocol': 'kernel',
153+
'metric': 256,
154+
'flags': [],
155+
'pref': 'medium'}]
156+
157+
Optionally, routes returned can be filtered with the following
158+
selectors. This can be useful in busy routing tables.
159+
160+
* table
161+
* device (maps to ip-route's 'dev' selector)
162+
* scope
163+
* proto
164+
* src
165+
* metric
166+
167+
"""
168+
169+
def rules(
170+
self,
171+
src=None,
172+
to=None,
173+
tos=None,
174+
fwmark=None,
175+
iif=None,
176+
oif=None,
177+
pref=None,
178+
uidrange=None,
179+
ipproto=None,
180+
sport=None,
181+
dport=None,
182+
):
183+
"""Returns the rules our routing policy consists of.
184+
185+
>>> host.iproute2.rules()
186+
[{'priority': 0, 'src': 'all', 'table': 'local'},
187+
{'priority': 32765, 'src': '1.2.3.4', 'table': '123'},
188+
{'priority': 32766, 'src': 'all', 'table': 'main'},
189+
{'priority': 32767, 'src': 'all', 'table': 'default'}]
190+
191+
Optionally, rules returned can be filtered with the following
192+
selectors. This can be useful in busy rulesets.
193+
194+
* src (maps to ip-rule's 'from' selector)
195+
* to
196+
* tos
197+
* fwmark
198+
* iif
199+
* oif
200+
* pref
201+
* uidrange
202+
* ipproto
203+
* sport
204+
* dport
205+
206+
"""
207+
208+
def tunnels(self, ifname=None):
209+
"""Returns all configured tunnels
210+
211+
>>> host.iproute2.tunnels()
212+
[{'ifname': 'test1',
213+
'mode': 'ip/ip',
214+
'remote': '127.0.0.2',
215+
'local': '0.0.0.0'}]
216+
217+
Optionally, tunnels returned can be filtered with the interface name.
218+
This can be faster in busy tunnel installations.
219+
220+
* ifname
221+
222+
"""
223+
224+
def vrfs(self):
225+
"""Returns all configured vrfs"""
226+
cmd = f"{self._ip} --json vrf show"
227+
out = self.check_output(cmd)
228+
return json.loads(out)
229+
230+
def netns(self):
231+
"""Returns all configured network namespaces
232+
233+
>>> host.iproute2.netns()
234+
[{'name': 'test'}]
235+
"""
236+
237+
def bridge_vlan(self):
238+
"""Returns all configured vlans
239+
240+
>>> host.iproute2.bridge_vlan()
241+
[]
242+
"""
243+
244+
def bridge_fdb(self):
245+
"""Returns all configured fdb entries
246+
247+
>>> host.iproute2.bridge_fdb()
248+
[{'mac': '33:33:00:00:00:01',
249+
'ifname': 'enp0s31f6',
250+
'flags': ['self'],
251+
'state': 'permanent'}]
252+
"""
253+
254+
def bridge_mdb(self):
255+
"""Returns all configured mdb entries
256+
257+
>>> host.iproute2.bridge_mdb()
258+
[{'mdb': [], 'router': {}}]
259+
260+
"""
261+
262+
def bridge_link(self):
263+
"""Returns all configured links
264+
265+
>>> host.iproute2.bridge_link()
266+
[]
267+
"""
268+
269+
270+
class LinuxIProute2(IProute2):
54271
@functools.cached_property
55272
def _ip(self):
56273
ip_cmd = self.find_command("ip")
@@ -326,9 +543,9 @@ def vrfs(self):
326543
def netns(self):
327544
"""Returns all configured network namespaces
328545
329-
>>> host.iproute2.netns()
330-
[{'name': 'test'}]
331-
"""
546+
>>> host.iproute2.netns()
547+
[{'name': 'test'}]
548+
"""
332549

333550
cmd = f"{self._ip} --json netns show"
334551
out = self.check_output(cmd)
@@ -339,9 +556,9 @@ def netns(self):
339556
def bridge_vlan(self):
340557
"""Returns all configured vlans
341558
342-
>>> host.iproute2.bridge_vlan()
343-
[]
344-
"""
559+
>>> host.iproute2.bridge_vlan()
560+
[]
561+
"""
345562

346563
cmd = f"{self._bridge} -json vlan show"
347564
out = self.check_output(cmd)
@@ -350,11 +567,11 @@ def bridge_vlan(self):
350567
def bridge_fdb(self):
351568
"""Returns all configured fdb entries
352569
353-
>>> host.iproute2.bridge_fdb()
354-
[{'mac': '33:33:00:00:00:01',
355-
'ifname': 'enp0s31f6',
356-
'flags': ['self'],
357-
'state': 'permanent'}]
570+
>>> host.iproute2.bridge_fdb()
571+
[{'mac': '33:33:00:00:00:01',
572+
'ifname': 'enp0s31f6',
573+
'flags': ['self'],
574+
'state': 'permanent'}]
358575
"""
359576

360577
cmd = f"{self._bridge} -json fdb show"
@@ -364,10 +581,10 @@ def bridge_fdb(self):
364581
def bridge_mdb(self):
365582
"""Returns all configured mdb entries
366583
367-
>>> host.iproute2.bridge_mdb()
368-
[{'mdb': [], 'router': {}}]
584+
>>> host.iproute2.bridge_mdb()
585+
[{'mdb': [], 'router': {}}]
369586
370-
"""
587+
"""
371588

372589
cmd = f"{self._bridge} -json mdb show"
373590
out = self.check_output(cmd)
@@ -376,9 +593,9 @@ def bridge_mdb(self):
376593
def bridge_link(self):
377594
"""Returns all configured links
378595
379-
>>> host.iproute2.bridge_link()
380-
[]
381-
"""
596+
>>> host.iproute2.bridge_link()
597+
[]
598+
"""
382599

383600
cmd = f"{self._bridge} -json link show"
384601
out = self.check_output(cmd)

0 commit comments

Comments
 (0)