Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve reliability of facts.hardware.NetworkDevices #1098

Merged
merged 4 commits into from
May 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
52 changes: 30 additions & 22 deletions pyinfra/facts/hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,28 +195,36 @@ def mask(value):
output = "\n".join(map(str.strip, output))

# Splitting the output into sections per network device
device_sections = re.split(r"\n(?=\d+: \w|\w+:.*mtu.*)", output)
device_sections = re.split(r"\n(?=\d+: [^\s/:]|[^\s/:]+:.*mtu )", output)

# Dictionary to hold all device information
all_devices = {}

for section in device_sections:
# Extracting the device name
device_name_match = re.match(r"^(?:\d+: )?([\w@]+):", section)
device_name_match = re.match(r"^(?:\d+: )?([^\s/:]+):", section)
if not device_name_match:
continue
device_name = device_name_match.group(1)

# Regular expressions to match different parts of the output
ether_re = re.compile(r"([0-9A-Fa-f:]{17})")
ether_re = re.compile(r"ether ([0-9A-Fa-f:]{17})")
mtu_re = re.compile(r"mtu (\d+)")
ipv4_re = (
# ip a
re.compile(
r"inet (\d+\.\d+\.\d+\.\d+)/(\d+)(?: brd (\d+\.\d+\.\d+\.\d+))"
), # ip a output,
r"inet (?P<address>\d+\.\d+\.\d+\.\d+)/(?P<mask>\d+)(?: metric \d+)?(?: brd (?P<broadcast>\d+\.\d+\.\d+\.\d+))?" # noqa: E501
),
# ifconfig -a
re.compile(
r"inet (\d+\.\d+\.\d+\.\d+)\s+netmask\s+((?:\d+\.\d+\.\d+\.\d+)|(?:[0-9a-fA-FxX]+))(?:\s+broadcast\s+(\d+\.\d+\.\d+\.\d+))" # noqa: E501
), # ifconfig -a output
r"inet (?P<address>\d+\.\d+\.\d+\.\d+)\s+netmask\s+(?P<mask>(?:\d+\.\d+\.\d+\.\d+)|(?:[0-9a-fA-FxX]+))(?:\s+broadcast\s+(?P<broadcast>\d+\.\d+\.\d+\.\d+))?" # noqa: E501
),
)
ipv6_re = (
# ip a
re.compile(r"inet6\s+(?P<address>[0-9a-fA-F:]+)/(?P<mask>\d+)"),
# ifconfig -a
re.compile(r"inet6\s+(?P<address>[0-9a-fA-F:]+)\s+prefixlen\s+(?P<mask>\d+)"),
)

# Parsing the output
Expand All @@ -235,18 +243,22 @@ def mask(value):
)

# IPv4 Addresses
ipv4_matches: list[re.Match[str]]
for ipv4_re_ in ipv4_re:
ipv4_matches = ipv4_re_.findall(section)
if ipv4_matches:
ipv4_matches = list(ipv4_re_.finditer(section))
if len(ipv4_matches):
break

if ipv4_matches:
if len(ipv4_matches):
ipv4_info = []
for ipv4 in ipv4_matches:
address = ipv4[0]
mask_value = ipv4[1]
address = ipv4.group("address")
mask_value = ipv4.group("mask")
mask_bits, netmask = mask(mask_value)
broadcast = ipv4[2] if len(ipv4) == 3 else None
try:
broadcast = ipv4.group("broadcast")
except IndexError:
broadcast = None

ipv4_info.append(
{
Expand All @@ -261,21 +273,17 @@ def mask(value):
device_info["ipv4"]["additional_ips"] = ipv4_info[1:] # type: ignore[index]

# IPv6 Addresses
ipv6_re = (
re.compile(r"inet6\s+([0-9a-fA-F:]+)/(\d+)"),
re.compile(r"inet6\s+([0-9a-fA-F:]+)\s+prefixlen\s+(\d+)"),
)

ipv6_matches: list[re.Match[str]]
for ipv6_re_ in ipv6_re:
ipv6_matches = ipv6_re_.findall(section)
ipv6_matches = list(ipv6_re_.finditer(section))
if ipv6_matches:
break

if ipv6_matches:
if len(ipv6_matches):
ipv6_info = []
for ipv6 in ipv6_matches:
address = ipv6[0]
mask_bits = ipv6[1] or ipv6[2]
address = ipv6.group("address")
mask_bits = ipv6.group("mask")
ipv6_info.append({"address": address, "mask_bits": int(mask_bits)})
device_info["ipv6"] = ipv6_info[0]
if len(ipv6_matches) > 1:
Expand Down
10 changes: 8 additions & 2 deletions tests/facts/hardware.NetworkDevices/linux_ifconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
],
"fact": {
"enp1s0": {
"ether": "2a01:e0a:5c2:7450",
"ether": "b0:41:6f:0a:cf:22",
"mtu": 1500,
"state": "UP",
"ipv4": {
Expand All @@ -51,7 +51,7 @@
}
},
"incusbr0": {
"ether": "fe80::216:3eff:fe",
"ether": "00:16:3e:9c:82:00",
"mtu": 1500,
"state": "UP",
"ipv4": {
Expand All @@ -74,6 +74,12 @@
"lo": {
"mtu": 65536,
"state": "UP",
"ipv4": {
"address": "127.0.0.1",
"mask_bits": 8,
"netmask": "255.0.0.0",
"broadcast": null
},
"ipv6": {
"address": "::1",
"mask_bits": 128
Expand Down
197 changes: 197 additions & 0 deletions tests/facts/hardware.NetworkDevices/linux_ifconfig_multiple.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
{
"command": "ip addr show 2> /dev/null || ifconfig -a",
"output": [
"myvlan: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500",
" inet 10.42.13.147 netmask 255.255.255.0 broadcast 10.42.13.255",
" inet6 fe80::3cd2:56ff:fe4d:1af2 prefixlen 64 scopeid 0x20<link>",
" ether 3e:d2:56:4d:1a:f2 txqueuelen 1000 (Ethernet)",
" RX packets 115016 bytes 28450084 (27.1 MiB)",
" RX errors 0 dropped 0 overruns 0 frame 0",
" TX packets 53310 bytes 9803632 (9.3 MiB)",
" TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0",
"",
"eno1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500",
" inet 10.42.6.142 netmask 255.255.255.0 broadcast 10.42.6.255",
" inet6 fe80::3cd2:56ff:fe4d:1af1 prefixlen 64 scopeid 0x20<link>",
" ether 3e:d2:56:4d:1a:f1 txqueuelen 1000 (Ethernet)",
" RX packets 5097072 bytes 4315873036 (4.0 GiB)",
" RX errors 0 dropped 0 overruns 0 frame 0",
" TX packets 3897172 bytes 1574206075 (1.4 GiB)",
" TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0",
"",
"lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536",
" inet 127.0.0.1 netmask 255.0.0.0",
" inet6 ::1 prefixlen 128 scopeid 0x10<host>",
" loop txqueuelen 1000 (Local Loopback)",
" RX packets 9470290 bytes 4905913998 (4.5 GiB)",
" RX errors 0 dropped 0 overruns 0 frame 0",
" TX packets 9470290 bytes 4905913998 (4.5 GiB)",
" TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0",
"",
"my-vpn: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1300",
" inet 10.66.7.3 netmask 255.255.255.0 destination 10.66.7.3",
" inet6 fe80::c9fc:e8d5:12d8:cfb2 prefixlen 64 scopeid 0x20<link>",
" unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 500 (UNSPEC)",
" RX packets 59069 bytes 22687707 (21.6 MiB)",
" RX errors 0 dropped 0 overruns 0 frame 0",
" TX packets 55603 bytes 8340765 (7.9 MiB)",
" TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0",
"",
"some-br: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500",
" inet 192.168.101.1 netmask 255.255.255.0 broadcast 0.0.0.0",
" inet6 fe80::f884:69ff:fe0a:a073 prefixlen 64 scopeid 0x20<link>",
" ether 8e:15:02:8a:7f:ee txqueuelen 1000 (Ethernet)",
" RX packets 1315769 bytes 616685980 (588.1 MiB)",
" RX errors 0 dropped 0 overruns 0 frame 0",
" TX packets 1434638 bytes 628356665 (599.2 MiB)",
" TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0",
"",
"some-tap: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500",
" inet6 fe80::f884:69ff:fe0a:a073 prefixlen 64 scopeid 0x20<link>",
" ether fa:84:69:0a:a0:73 txqueuelen 1000 (Ethernet)",
" RX packets 1315769 bytes 635106746 (605.6 MiB)",
" RX errors 0 dropped 0 overruns 0 frame 0",
" TX packets 1450904 bytes 631656508 (602.3 MiB)",
" TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0",
"",
"vmbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500",
" inet 172.20.0.2 netmask 255.255.255.0 broadcast 172.20.0.255",
" ether 7a:c8:eb:21:98:98 txqueuelen 1000 (Ethernet)",
" RX packets 0 bytes 0 (0.0 B)",
" RX errors 0 dropped 0 overruns 0 frame 0",
" TX packets 0 bytes 0 (0.0 B)",
" TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0",
"",
"vmbr0-veth: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500",
" ether 52:a5:03:cb:ee:31 txqueuelen 1000 (Ethernet)",
" RX packets 0 bytes 0 (0.0 B)",
" RX errors 0 dropped 0 overruns 0 frame 0",
" TX packets 0 bytes 0 (0.0 B)",
" TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0",
"",
"vmbr0-veth-end: flags=4098<BROADCAST,MULTICAST> mtu 1500",
" ether 96:1d:5c:3b:20:9e txqueuelen 1000 (Ethernet)",
" RX packets 0 bytes 0 (0.0 B)",
" RX errors 0 dropped 0 overruns 0 frame 0",
" TX packets 0 bytes 0 (0.0 B)",
" TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0",
"",
"wlp6s0: flags=4098<BROADCAST,MULTICAST> mtu 1500",
" ether b8:4c:68:59:45:7d txqueuelen 1000 (Ethernet)",
" RX packets 0 bytes 0 (0.0 B)",
" RX errors 0 dropped 0 overruns 0 frame 0",
" TX packets 0 bytes 0 (0.0 B)",
" TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0",
""
],
"fact": {
"lo": {
"mtu": 65536,
"state": "UP",
"ipv4": {
"address": "127.0.0.1",
"mask_bits": 8,
"netmask": "255.0.0.0",
"broadcast": null
},
"ipv6": {
"address": "::1",
"mask_bits": 128
}
},
"eno1": {
"ether": "3e:d2:56:4d:1a:f1",
"mtu": 1500,
"state": "UP",
"ipv4": {
"address": "10.42.6.142",
"mask_bits": 24,
"netmask": "255.255.255.0",
"broadcast": "10.42.6.255"
},
"ipv6": {
"address": "fe80::3cd2:56ff:fe4d:1af1",
"mask_bits": 64
}
},
"wlp6s0": {
"ether": "b8:4c:68:59:45:7d",
"mtu": 1500,
"state": "UNKNOWN"
},
"myvlan": {
"ether": "3e:d2:56:4d:1a:f2",
"mtu": 1500,
"state": "UP",
"ipv4": {
"address": "10.42.13.147",
"mask_bits": 24,
"netmask": "255.255.255.0",
"broadcast": "10.42.13.255"
},
"ipv6": {
"address": "fe80::3cd2:56ff:fe4d:1af2",
"mask_bits": 64
}
},
"vmbr0": {
"ether": "7a:c8:eb:21:98:98",
"mtu": 1500,
"state": "UP",
"ipv4": {
"address": "172.20.0.2",
"mask_bits": 24,
"netmask": "255.255.255.0",
"broadcast": "172.20.0.255"
}
},
"vmbr0-veth-end": {
"ether": "96:1d:5c:3b:20:9e",
"mtu": 1500,
"state": "UNKNOWN"
},
"vmbr0-veth": {
"ether": "52:a5:03:cb:ee:31",
"mtu": 1500,
"state": "UP"
},
"some-tap": {
"ether": "fa:84:69:0a:a0:73",
"mtu": 1500,
"state": "UP",
"ipv6": {
"address": "fe80::f884:69ff:fe0a:a073",
"mask_bits": 64
}
},
"some-br": {
"ether": "8e:15:02:8a:7f:ee",
"mtu": 1500,
"state": "UP",
"ipv4": {
"address": "192.168.101.1",
"mask_bits": 24,
"netmask": "255.255.255.0",
"broadcast": "0.0.0.0"
},
"ipv6": {
"address": "fe80::f884:69ff:fe0a:a073",
"mask_bits": 64
}
},
"my-vpn": {
"mtu": 1300,
"state": "UP",
"ipv4": {
"address": "10.66.7.3",
"mask_bits": 24,
"netmask": "255.255.255.0",
"broadcast": null
},
"ipv6": {
"address": "fe80::c9fc:e8d5:12d8:cfb2",
"mask_bits": 64
}
}
}
}