linuxfabrik-lib 4.3.0__tar.gz → 4.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/PKG-INFO +1 -2
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/disk.py +31 -1
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/endoflifedate.py +8 -2
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/linuxfabrik_lib.egg-info/PKG-INFO +1 -2
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/linuxfabrik_lib.egg-info/requires.txt +0 -1
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/net.py +151 -43
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/pyproject.toml +1 -2
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/redfish.py +651 -20
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/time.py +26 -7
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/url.py +38 -27
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/LICENSE +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/README.md +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/__init__.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/args.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/base.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/cache.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/db_mysql.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/db_sqlite.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/distro.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/dmidecode.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/feedparser.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/globals.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/grassfish.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/huawei.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/human.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/icinga.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/infomaniak.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/jitsi.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/keycloak.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/lftest.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/librenms.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/linuxfabrik_lib.egg-info/SOURCES.txt +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/linuxfabrik_lib.egg-info/dependency_links.txt +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/linuxfabrik_lib.egg-info/top_level.txt +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/nextcloud.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/nodebb.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/powershell.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/psutil.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/qts.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/rocket.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/setup.cfg +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/shell.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/smb.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/ssh.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/txt.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/uptimerobot.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/veeam.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/version.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/wildfly.py +0 -0
- {linuxfabrik_lib-4.3.0 → linuxfabrik_lib-4.4.0}/winrm.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: linuxfabrik-lib
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.4.0
|
|
4
4
|
Summary: Python libraries used in various Linuxfabrik projects, including the 'Linuxfabrik Monitoring Plugins' project.
|
|
5
5
|
Author-email: "Linuxfabrik GmbH, Zurich, Switzerland" <info@linuxfabrik.ch>
|
|
6
6
|
License: This is free and unencumbered software released into the public domain.
|
|
@@ -59,7 +59,6 @@ License-File: LICENSE
|
|
|
59
59
|
Requires-Dist: beautifulsoup4
|
|
60
60
|
Requires-Dist: httpx[http2]
|
|
61
61
|
Requires-Dist: lxml
|
|
62
|
-
Requires-Dist: netifaces
|
|
63
62
|
Requires-Dist: psutil
|
|
64
63
|
Requires-Dist: pymysql
|
|
65
64
|
Requires-Dist: pypsrp
|
|
@@ -13,7 +13,7 @@ partitions, grepping a file, etc.
|
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
|
|
16
|
-
__version__ = '
|
|
16
|
+
__version__ = '2026060801'
|
|
17
17
|
|
|
18
18
|
import csv
|
|
19
19
|
import os
|
|
@@ -693,6 +693,36 @@ def rm_file(filename):
|
|
|
693
693
|
return False, f'Unknown error deleting {filename}: {e}'
|
|
694
694
|
|
|
695
695
|
|
|
696
|
+
def shorten_path(path):
|
|
697
|
+
"""
|
|
698
|
+
Shorten a path for display.
|
|
699
|
+
|
|
700
|
+
Abbreviate a slash-separated path by reducing every component except the last one to its
|
|
701
|
+
first character, the way the zsh prompt shortens a long working directory. The last
|
|
702
|
+
component is kept in full because it usually carries the identifying information. This is
|
|
703
|
+
a pure string transformation; the path is not resolved and the filesystem is not touched.
|
|
704
|
+
|
|
705
|
+
### Parameters
|
|
706
|
+
- **path** (`str`): A slash-separated path, for example `/etc/pki/tls/certs/002c0b4f.0`.
|
|
707
|
+
|
|
708
|
+
### Returns
|
|
709
|
+
- **str**: The abbreviated path, for example `/e/p/t/c/002c0b4f.0`. A value without a
|
|
710
|
+
slash (a bare basename, an empty string, a sentinel like `-`) is returned unchanged.
|
|
711
|
+
|
|
712
|
+
### Example
|
|
713
|
+
>>> shorten_path('/etc/pki/tls/certs/002c0b4f.0')
|
|
714
|
+
'/e/p/t/c/002c0b4f.0'
|
|
715
|
+
|
|
716
|
+
>>> shorten_path('index.php')
|
|
717
|
+
'index.php'
|
|
718
|
+
"""
|
|
719
|
+
if not path or '/' not in path:
|
|
720
|
+
return path
|
|
721
|
+
head, _, tail = path.rpartition('/')
|
|
722
|
+
abbrev = '/'.join(part[:1] for part in head.split('/'))
|
|
723
|
+
return f'{abbrev}/{tail}'
|
|
724
|
+
|
|
725
|
+
|
|
696
726
|
def udevadm(device, _property):
|
|
697
727
|
"""
|
|
698
728
|
Run `udevadm info` and extract a specific property manually.
|
|
@@ -1927,8 +1927,8 @@ ENDOFLIFE_DATE = {
|
|
|
1927
1927
|
'https://endoflife.date/api/matomo.json': [
|
|
1928
1928
|
{ 'cycle': '5',
|
|
1929
1929
|
'eol': False,
|
|
1930
|
-
'latest': '5.
|
|
1931
|
-
'latestReleaseDate': '2026-
|
|
1930
|
+
'latest': '5.11.0',
|
|
1931
|
+
'latestReleaseDate': '2026-06-09',
|
|
1932
1932
|
'lts': False,
|
|
1933
1933
|
'releaseDate': '2023-12-18',
|
|
1934
1934
|
'support': True},
|
|
@@ -1964,6 +1964,12 @@ ENDOFLIFE_DATE = {
|
|
|
1964
1964
|
|
|
1965
1965
|
|
|
1966
1966
|
'https://endoflife.date/api/mediawiki.json': [
|
|
1967
|
+
{ 'cycle': '1.46',
|
|
1968
|
+
'eol': '2027-05-31',
|
|
1969
|
+
'latest': '1.46.0',
|
|
1970
|
+
'latestReleaseDate': '2026-05-31',
|
|
1971
|
+
'lts': False,
|
|
1972
|
+
'releaseDate': '2026-05-31'},
|
|
1967
1973
|
{ 'cycle': '1.45',
|
|
1968
1974
|
'eol': '2026-12-31',
|
|
1969
1975
|
'latest': '1.45.3',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: linuxfabrik-lib
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.4.0
|
|
4
4
|
Summary: Python libraries used in various Linuxfabrik projects, including the 'Linuxfabrik Monitoring Plugins' project.
|
|
5
5
|
Author-email: "Linuxfabrik GmbH, Zurich, Switzerland" <info@linuxfabrik.ch>
|
|
6
6
|
License: This is free and unencumbered software released into the public domain.
|
|
@@ -59,7 +59,6 @@ License-File: LICENSE
|
|
|
59
59
|
Requires-Dist: beautifulsoup4
|
|
60
60
|
Requires-Dist: httpx[http2]
|
|
61
61
|
Requires-Dist: lxml
|
|
62
|
-
Requires-Dist: netifaces
|
|
63
62
|
Requires-Dist: psutil
|
|
64
63
|
Requires-Dist: pymysql
|
|
65
64
|
Requires-Dist: pypsrp
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"""Provides network related functions and variables."""
|
|
13
13
|
|
|
14
14
|
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
|
|
15
|
-
__version__ = '
|
|
15
|
+
__version__ = '2026060901'
|
|
16
16
|
|
|
17
17
|
import ipaddress
|
|
18
18
|
import random
|
|
@@ -21,11 +21,11 @@ import socket
|
|
|
21
21
|
import ssl
|
|
22
22
|
|
|
23
23
|
try:
|
|
24
|
-
import
|
|
24
|
+
import psutil
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
HAVE_PSUTIL = True
|
|
27
27
|
except ImportError:
|
|
28
|
-
|
|
28
|
+
HAVE_PSUTIL = False
|
|
29
29
|
|
|
30
30
|
from . import (
|
|
31
31
|
txt, # pylint: disable=C0413
|
|
@@ -459,12 +459,98 @@ def fetch_ssl(host, port, msg=None, timeout=3):
|
|
|
459
459
|
return False, f'Could not open SSL socket: {e}'
|
|
460
460
|
|
|
461
461
|
|
|
462
|
+
def _default_route_ip(family=socket.AF_INET):
|
|
463
|
+
"""
|
|
464
|
+
Return the local IP address the kernel would use for the default route, or `None`.
|
|
465
|
+
|
|
466
|
+
Opens a connected UDP socket towards an off-link address and reads back the source address the
|
|
467
|
+
routing table selects. UDP `connect` only sets the peer, so no packet is sent; this works on
|
|
468
|
+
Linux, Windows and macOS without external tools or privileges, and offline as long as a default
|
|
469
|
+
route exists.
|
|
470
|
+
|
|
471
|
+
### Parameters
|
|
472
|
+
- **family** (`int`, optional): `socket.AF_INET` (default) or `socket.AF_INET6`.
|
|
473
|
+
|
|
474
|
+
### Returns
|
|
475
|
+
- **str** or **None**: The selected source address, or `None` if no route is available.
|
|
476
|
+
"""
|
|
477
|
+
probe = '192.0.2.1' if family == socket.AF_INET else '2001:db8::1'
|
|
478
|
+
try:
|
|
479
|
+
sock = socket.socket(family, socket.SOCK_DGRAM)
|
|
480
|
+
except OSError:
|
|
481
|
+
return None
|
|
482
|
+
try:
|
|
483
|
+
sock.connect((probe, 9))
|
|
484
|
+
return sock.getsockname()[0].split('%')[0]
|
|
485
|
+
except OSError:
|
|
486
|
+
return None
|
|
487
|
+
finally:
|
|
488
|
+
sock.close()
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
def _default_gateway():
|
|
492
|
+
"""
|
|
493
|
+
Return the IPv4 default gateway address, or `None` if it cannot be determined.
|
|
494
|
+
|
|
495
|
+
Reads the kernel routing table from `/proc/net/route` (Linux). On platforms without that file
|
|
496
|
+
the gateway is not available through a dependency-free, cross-platform API, so `None` is
|
|
497
|
+
returned rather than guessing.
|
|
498
|
+
|
|
499
|
+
### Returns
|
|
500
|
+
- **str** or **None**: The default gateway IPv4 address, or `None`.
|
|
501
|
+
"""
|
|
502
|
+
try:
|
|
503
|
+
with open('/proc/net/route', encoding='ascii') as routes:
|
|
504
|
+
for line in routes.read().splitlines()[1:]:
|
|
505
|
+
fields = line.split()
|
|
506
|
+
# Destination 00000000 marks the default route; flags must have RTF_GATEWAY (0x2).
|
|
507
|
+
if (
|
|
508
|
+
len(fields) > 3
|
|
509
|
+
and fields[1] == '00000000'
|
|
510
|
+
and int(fields[3], 16) & 0x2
|
|
511
|
+
):
|
|
512
|
+
# The gateway is a little-endian hex IPv4 in column 2.
|
|
513
|
+
return socket.inet_ntoa(bytes.fromhex(fields[2])[::-1])
|
|
514
|
+
except (OSError, ValueError):
|
|
515
|
+
return None
|
|
516
|
+
return None
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
def _iface_for_ip(ip):
|
|
520
|
+
"""
|
|
521
|
+
Return `(interface_name, netmask)` for the interface carrying `ip`, or `(None, None)`.
|
|
522
|
+
|
|
523
|
+
Matches the address against psutil's per-interface address list, so it is platform-independent.
|
|
524
|
+
|
|
525
|
+
### Parameters
|
|
526
|
+
- **ip** (`str`): The IPv4 or IPv6 address to look up.
|
|
527
|
+
|
|
528
|
+
### Returns
|
|
529
|
+
- **tuple** (`str` or `None`, `str` or `None`): The interface name and its netmask.
|
|
530
|
+
"""
|
|
531
|
+
try:
|
|
532
|
+
wanted = ipaddress.ip_address(ip)
|
|
533
|
+
except ValueError:
|
|
534
|
+
return (None, None)
|
|
535
|
+
for iface, addrs in psutil.net_if_addrs().items():
|
|
536
|
+
for addr in addrs:
|
|
537
|
+
if addr.family not in (socket.AF_INET, socket.AF_INET6):
|
|
538
|
+
continue
|
|
539
|
+
try:
|
|
540
|
+
if ipaddress.ip_address((addr.address or '').split('%')[0]) == wanted:
|
|
541
|
+
return (iface, addr.netmask)
|
|
542
|
+
except ValueError:
|
|
543
|
+
continue
|
|
544
|
+
return (None, None)
|
|
545
|
+
|
|
546
|
+
|
|
462
547
|
def get_netinfo():
|
|
463
548
|
"""
|
|
464
549
|
Retrieve local and public network information.
|
|
465
550
|
|
|
466
551
|
This function retrieves the system's primary IP address, netmask, CIDR mask, default gateway,
|
|
467
|
-
and public IP address.
|
|
552
|
+
and public IP address. Addresses come from `psutil` (platform-independent); the default gateway
|
|
553
|
+
is read from the Linux routing table and is `None` on other platforms.
|
|
468
554
|
|
|
469
555
|
### Parameters
|
|
470
556
|
- None
|
|
@@ -475,12 +561,12 @@ def get_netinfo():
|
|
|
475
561
|
- `address` (`str`): The local IP address.
|
|
476
562
|
- `mask` (`str`): The subnet mask.
|
|
477
563
|
- `mask_cidr` (`str`): The subnet mask as CIDR.
|
|
478
|
-
- `gateway` (`str`): The default gateway address.
|
|
564
|
+
- `gateway` (`str` or `None`): The default gateway address.
|
|
479
565
|
- `public_address` (`str`): The public IP address.
|
|
480
566
|
|
|
481
567
|
### Notes
|
|
482
568
|
- If fetching any required information fails, an empty list is returned.
|
|
483
|
-
- Requires `
|
|
569
|
+
- Requires `psutil` and the `ip_to_cidr()` helper.
|
|
484
570
|
- The `public_address` field is always `None`; callers that want the public
|
|
485
571
|
IP must call `get_public_ip()` separately with a list of lookup services.
|
|
486
572
|
|
|
@@ -489,25 +575,24 @@ def get_netinfo():
|
|
|
489
575
|
>>> print(netinfo['address'])
|
|
490
576
|
'192.168.1.10'
|
|
491
577
|
"""
|
|
492
|
-
if not
|
|
578
|
+
if not HAVE_PSUTIL:
|
|
493
579
|
return []
|
|
494
580
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
return {
|
|
501
|
-
'address': iface_addrs.get('addr'),
|
|
502
|
-
'mask': iface_addrs.get('netmask'),
|
|
503
|
-
'mask_cidr': ip_to_cidr(iface_addrs.get('netmask')),
|
|
504
|
-
'gateway': default_gateway[0],
|
|
505
|
-
'public_address': None,
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
except (KeyError, AttributeError, IndexError):
|
|
581
|
+
address = _default_route_ip(socket.AF_INET)
|
|
582
|
+
if not address:
|
|
583
|
+
return []
|
|
584
|
+
iface, netmask = _iface_for_ip(address)
|
|
585
|
+
if not iface or not netmask:
|
|
509
586
|
return []
|
|
510
587
|
|
|
588
|
+
return {
|
|
589
|
+
'address': address,
|
|
590
|
+
'mask': netmask,
|
|
591
|
+
'mask_cidr': ip_to_cidr(netmask),
|
|
592
|
+
'gateway': _default_gateway(),
|
|
593
|
+
'public_address': None,
|
|
594
|
+
}
|
|
595
|
+
|
|
511
596
|
|
|
512
597
|
def get_public_ip(services, insecure=False, no_proxy=False, timeout=2):
|
|
513
598
|
"""
|
|
@@ -597,6 +682,30 @@ def cidr_to_hosts(cidr, max_hosts=65536):
|
|
|
597
682
|
return (True, [str(host) for host in network.hosts()])
|
|
598
683
|
|
|
599
684
|
|
|
685
|
+
def _ipv6_prefixlen(netmask):
|
|
686
|
+
"""
|
|
687
|
+
Return the prefix length (as a string) for an IPv6 netmask reported by psutil.
|
|
688
|
+
|
|
689
|
+
psutil reports the IPv6 netmask either as a full mask ("ffff:ffff:ffff:ffff::"), as a
|
|
690
|
+
"mask/prefix" string, or as `None`. All three are normalised to a prefix length, defaulting to
|
|
691
|
+
"128" (a single host) when it cannot be derived.
|
|
692
|
+
|
|
693
|
+
### Parameters
|
|
694
|
+
- **netmask** (`str` or `None`): The IPv6 netmask as reported by psutil.
|
|
695
|
+
|
|
696
|
+
### Returns
|
|
697
|
+
- **str**: The prefix length, e.g. "64".
|
|
698
|
+
"""
|
|
699
|
+
if not netmask:
|
|
700
|
+
return '128'
|
|
701
|
+
if '/' in netmask:
|
|
702
|
+
return netmask.split('/')[-1]
|
|
703
|
+
try:
|
|
704
|
+
return str(bin(int(ipaddress.IPv6Address(netmask))).count('1'))
|
|
705
|
+
except ipaddress.AddressValueError:
|
|
706
|
+
return '128'
|
|
707
|
+
|
|
708
|
+
|
|
600
709
|
def get_subnet_hosts(interface=None, max_hosts=65536):
|
|
601
710
|
"""
|
|
602
711
|
Return the usable host IP addresses of an interface's subnet.
|
|
@@ -620,14 +729,14 @@ def get_subnet_hosts(interface=None, max_hosts=65536):
|
|
|
620
729
|
- `False` and an error message on failure.
|
|
621
730
|
|
|
622
731
|
### Notes
|
|
623
|
-
- Requires the `
|
|
732
|
+
- Requires the `psutil` library.
|
|
624
733
|
|
|
625
734
|
### Example
|
|
626
735
|
>>> get_subnet_hosts('eth0')
|
|
627
736
|
(True, ['192.168.1.1', '192.168.1.2', ..., '192.168.1.254'])
|
|
628
737
|
"""
|
|
629
|
-
if not
|
|
630
|
-
return (False, 'Python module "
|
|
738
|
+
if not HAVE_PSUTIL:
|
|
739
|
+
return (False, 'Python module "psutil" is not installed.')
|
|
631
740
|
|
|
632
741
|
if interface is None:
|
|
633
742
|
netinfo = get_netinfo()
|
|
@@ -637,26 +746,25 @@ def get_subnet_hosts(interface=None, max_hosts=65536):
|
|
|
637
746
|
f'{netinfo["address"]}/{netinfo["mask_cidr"]}', max_hosts=max_hosts
|
|
638
747
|
)
|
|
639
748
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
except ValueError:
|
|
749
|
+
if_addrs = psutil.net_if_addrs()
|
|
750
|
+
if interface not in if_addrs:
|
|
643
751
|
return (False, f'No such interface "{interface}".')
|
|
644
752
|
|
|
645
|
-
# IPv4 first, then IPv6.
|
|
646
|
-
# "ffff:ffff:ffff:ffff
|
|
647
|
-
for family in (
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
753
|
+
# IPv4 first, then IPv6. psutil may suffix the address with a "%scope" and reports the IPv6
|
|
754
|
+
# netmask as a full mask ("ffff:ffff:ffff:ffff::") rather than a prefix length.
|
|
755
|
+
for family in (socket.AF_INET, socket.AF_INET6):
|
|
756
|
+
for addr in if_addrs[interface]:
|
|
757
|
+
if addr.family != family:
|
|
758
|
+
continue
|
|
759
|
+
address = (addr.address or '').split('%')[0]
|
|
760
|
+
netmask = addr.netmask or ''
|
|
761
|
+
if not address:
|
|
762
|
+
continue
|
|
763
|
+
if family == socket.AF_INET:
|
|
764
|
+
cidr = ip_to_cidr(netmask)
|
|
765
|
+
else:
|
|
766
|
+
cidr = _ipv6_prefixlen(netmask)
|
|
767
|
+
return cidr_to_hosts(f'{address}/{cidr}', max_hosts=max_hosts)
|
|
660
768
|
|
|
661
769
|
return (False, f'No IPv4 or IPv6 address found on interface "{interface}".')
|
|
662
770
|
|
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "linuxfabrik-lib"
|
|
9
|
-
version = "4.
|
|
9
|
+
version = "4.4.0"
|
|
10
10
|
description = "Python libraries used in various Linuxfabrik projects, including the 'Linuxfabrik Monitoring Plugins' project."
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
authors = [
|
|
@@ -40,7 +40,6 @@ dependencies = [
|
|
|
40
40
|
"beautifulsoup4",
|
|
41
41
|
"httpx[http2]",
|
|
42
42
|
"lxml",
|
|
43
|
-
"netifaces",
|
|
44
43
|
"psutil",
|
|
45
44
|
"pymysql",
|
|
46
45
|
"pypsrp",
|