pyinfra 0.11.dev3__py3-none-any.whl → 3.6__py3-none-any.whl
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.
- pyinfra/__init__.py +9 -12
- pyinfra/__main__.py +4 -0
- pyinfra/api/__init__.py +19 -3
- pyinfra/api/arguments.py +413 -0
- pyinfra/api/arguments_typed.py +79 -0
- pyinfra/api/command.py +274 -0
- pyinfra/api/config.py +222 -28
- pyinfra/api/connect.py +33 -13
- pyinfra/api/connectors.py +27 -0
- pyinfra/api/deploy.py +65 -66
- pyinfra/api/exceptions.py +73 -18
- pyinfra/api/facts.py +267 -200
- pyinfra/api/host.py +416 -50
- pyinfra/api/inventory.py +121 -160
- pyinfra/api/metadata.py +69 -0
- pyinfra/api/operation.py +432 -262
- pyinfra/api/operations.py +273 -260
- pyinfra/api/state.py +302 -248
- pyinfra/api/util.py +309 -369
- pyinfra/connectors/base.py +173 -0
- pyinfra/connectors/chroot.py +212 -0
- pyinfra/connectors/docker.py +405 -0
- pyinfra/connectors/dockerssh.py +297 -0
- pyinfra/connectors/local.py +238 -0
- pyinfra/connectors/scp/__init__.py +1 -0
- pyinfra/connectors/scp/client.py +204 -0
- pyinfra/connectors/ssh.py +727 -0
- pyinfra/connectors/ssh_util.py +114 -0
- pyinfra/connectors/sshuserclient/client.py +309 -0
- pyinfra/connectors/sshuserclient/config.py +102 -0
- pyinfra/connectors/terraform.py +135 -0
- pyinfra/connectors/util.py +417 -0
- pyinfra/connectors/vagrant.py +183 -0
- pyinfra/context.py +145 -0
- pyinfra/facts/__init__.py +7 -6
- pyinfra/facts/apk.py +22 -7
- pyinfra/facts/apt.py +117 -60
- pyinfra/facts/brew.py +100 -15
- pyinfra/facts/bsdinit.py +23 -0
- pyinfra/facts/cargo.py +37 -0
- pyinfra/facts/choco.py +47 -0
- pyinfra/facts/crontab.py +195 -0
- pyinfra/facts/deb.py +94 -0
- pyinfra/facts/dnf.py +48 -0
- pyinfra/facts/docker.py +96 -23
- pyinfra/facts/efibootmgr.py +113 -0
- pyinfra/facts/files.py +629 -58
- pyinfra/facts/flatpak.py +77 -0
- pyinfra/facts/freebsd.py +70 -0
- pyinfra/facts/gem.py +19 -6
- pyinfra/facts/git.py +59 -14
- pyinfra/facts/gpg.py +150 -0
- pyinfra/facts/hardware.py +313 -167
- pyinfra/facts/iptables.py +72 -62
- pyinfra/facts/launchd.py +44 -0
- pyinfra/facts/lxd.py +17 -4
- pyinfra/facts/mysql.py +122 -86
- pyinfra/facts/npm.py +17 -9
- pyinfra/facts/openrc.py +71 -0
- pyinfra/facts/opkg.py +246 -0
- pyinfra/facts/pacman.py +50 -7
- pyinfra/facts/pip.py +24 -7
- pyinfra/facts/pipx.py +82 -0
- pyinfra/facts/pkg.py +15 -6
- pyinfra/facts/pkgin.py +35 -0
- pyinfra/facts/podman.py +54 -0
- pyinfra/facts/postgres.py +178 -0
- pyinfra/facts/postgresql.py +6 -147
- pyinfra/facts/rpm.py +105 -0
- pyinfra/facts/runit.py +77 -0
- pyinfra/facts/selinux.py +161 -0
- pyinfra/facts/server.py +762 -285
- pyinfra/facts/snap.py +88 -0
- pyinfra/facts/systemd.py +139 -0
- pyinfra/facts/sysvinit.py +59 -0
- pyinfra/facts/upstart.py +35 -0
- pyinfra/facts/util/__init__.py +17 -0
- pyinfra/facts/util/databases.py +4 -6
- pyinfra/facts/util/packaging.py +37 -6
- pyinfra/facts/util/units.py +30 -0
- pyinfra/facts/util/win_files.py +99 -0
- pyinfra/facts/vzctl.py +20 -13
- pyinfra/facts/xbps.py +35 -0
- pyinfra/facts/yum.py +34 -40
- pyinfra/facts/zfs.py +77 -0
- pyinfra/facts/zypper.py +42 -0
- pyinfra/local.py +45 -83
- pyinfra/operations/__init__.py +12 -0
- pyinfra/operations/apk.py +99 -0
- pyinfra/operations/apt.py +496 -0
- pyinfra/operations/brew.py +232 -0
- pyinfra/operations/bsdinit.py +59 -0
- pyinfra/operations/cargo.py +45 -0
- pyinfra/operations/choco.py +61 -0
- pyinfra/operations/crontab.py +194 -0
- pyinfra/operations/dnf.py +213 -0
- pyinfra/operations/docker.py +492 -0
- pyinfra/operations/files.py +2014 -0
- pyinfra/operations/flatpak.py +95 -0
- pyinfra/operations/freebsd/__init__.py +12 -0
- pyinfra/operations/freebsd/freebsd_update.py +70 -0
- pyinfra/operations/freebsd/pkg.py +219 -0
- pyinfra/operations/freebsd/service.py +116 -0
- pyinfra/operations/freebsd/sysrc.py +92 -0
- pyinfra/operations/gem.py +48 -0
- pyinfra/operations/git.py +420 -0
- pyinfra/operations/iptables.py +312 -0
- pyinfra/operations/launchd.py +45 -0
- pyinfra/operations/lxd.py +69 -0
- pyinfra/operations/mysql.py +610 -0
- pyinfra/operations/npm.py +57 -0
- pyinfra/operations/openrc.py +63 -0
- pyinfra/operations/opkg.py +89 -0
- pyinfra/operations/pacman.py +82 -0
- pyinfra/operations/pip.py +206 -0
- pyinfra/operations/pipx.py +103 -0
- pyinfra/operations/pkg.py +71 -0
- pyinfra/operations/pkgin.py +92 -0
- pyinfra/operations/postgres.py +437 -0
- pyinfra/operations/postgresql.py +30 -0
- pyinfra/operations/puppet.py +41 -0
- pyinfra/operations/python.py +73 -0
- pyinfra/operations/runit.py +184 -0
- pyinfra/operations/selinux.py +190 -0
- pyinfra/operations/server.py +1100 -0
- pyinfra/operations/snap.py +118 -0
- pyinfra/operations/ssh.py +217 -0
- pyinfra/operations/systemd.py +150 -0
- pyinfra/operations/sysvinit.py +142 -0
- pyinfra/operations/upstart.py +68 -0
- pyinfra/operations/util/__init__.py +12 -0
- pyinfra/operations/util/docker.py +407 -0
- pyinfra/operations/util/files.py +247 -0
- pyinfra/operations/util/packaging.py +338 -0
- pyinfra/operations/util/service.py +46 -0
- pyinfra/operations/vzctl.py +137 -0
- pyinfra/operations/xbps.py +78 -0
- pyinfra/operations/yum.py +213 -0
- pyinfra/operations/zfs.py +176 -0
- pyinfra/operations/zypper.py +193 -0
- pyinfra/progress.py +44 -32
- pyinfra/py.typed +0 -0
- pyinfra/version.py +9 -1
- pyinfra-3.6.dist-info/METADATA +142 -0
- pyinfra-3.6.dist-info/RECORD +160 -0
- {pyinfra-0.11.dev3.dist-info → pyinfra-3.6.dist-info}/WHEEL +1 -2
- pyinfra-3.6.dist-info/entry_points.txt +12 -0
- {pyinfra-0.11.dev3.dist-info → pyinfra-3.6.dist-info/licenses}/LICENSE.md +1 -1
- pyinfra_cli/__init__.py +1 -0
- pyinfra_cli/cli.py +793 -0
- pyinfra_cli/commands.py +66 -0
- pyinfra_cli/exceptions.py +155 -65
- pyinfra_cli/inventory.py +233 -89
- pyinfra_cli/log.py +39 -43
- pyinfra_cli/main.py +26 -495
- pyinfra_cli/prints.py +215 -156
- pyinfra_cli/util.py +172 -105
- pyinfra_cli/virtualenv.py +25 -20
- pyinfra/api/connectors/__init__.py +0 -21
- pyinfra/api/connectors/ansible.py +0 -99
- pyinfra/api/connectors/docker.py +0 -178
- pyinfra/api/connectors/local.py +0 -169
- pyinfra/api/connectors/ssh.py +0 -402
- pyinfra/api/connectors/sshuserclient/client.py +0 -105
- pyinfra/api/connectors/sshuserclient/config.py +0 -90
- pyinfra/api/connectors/util.py +0 -63
- pyinfra/api/connectors/vagrant.py +0 -155
- pyinfra/facts/init.py +0 -176
- pyinfra/facts/util/files.py +0 -102
- pyinfra/hook.py +0 -41
- pyinfra/modules/__init__.py +0 -11
- pyinfra/modules/apk.py +0 -64
- pyinfra/modules/apt.py +0 -272
- pyinfra/modules/brew.py +0 -122
- pyinfra/modules/files.py +0 -711
- pyinfra/modules/gem.py +0 -30
- pyinfra/modules/git.py +0 -115
- pyinfra/modules/init.py +0 -344
- pyinfra/modules/iptables.py +0 -271
- pyinfra/modules/lxd.py +0 -45
- pyinfra/modules/mysql.py +0 -347
- pyinfra/modules/npm.py +0 -47
- pyinfra/modules/pacman.py +0 -60
- pyinfra/modules/pip.py +0 -99
- pyinfra/modules/pkg.py +0 -43
- pyinfra/modules/postgresql.py +0 -245
- pyinfra/modules/puppet.py +0 -20
- pyinfra/modules/python.py +0 -37
- pyinfra/modules/server.py +0 -524
- pyinfra/modules/ssh.py +0 -150
- pyinfra/modules/util/files.py +0 -52
- pyinfra/modules/util/packaging.py +0 -118
- pyinfra/modules/vzctl.py +0 -133
- pyinfra/modules/yum.py +0 -171
- pyinfra/pseudo_modules.py +0 -64
- pyinfra-0.11.dev3.dist-info/.DS_Store +0 -0
- pyinfra-0.11.dev3.dist-info/METADATA +0 -135
- pyinfra-0.11.dev3.dist-info/RECORD +0 -95
- pyinfra-0.11.dev3.dist-info/entry_points.txt +0 -3
- pyinfra-0.11.dev3.dist-info/top_level.txt +0 -2
- pyinfra_cli/__main__.py +0 -40
- pyinfra_cli/config.py +0 -92
- /pyinfra/{modules/util → connectors}/__init__.py +0 -0
- /pyinfra/{api/connectors → connectors}/sshuserclient/__init__.py +0 -0
pyinfra/facts/hardware.py
CHANGED
|
@@ -1,51 +1,64 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import re
|
|
2
4
|
|
|
5
|
+
from typing_extensions import override
|
|
6
|
+
|
|
3
7
|
from pyinfra.api import FactBase, ShortFactBase
|
|
4
8
|
|
|
5
9
|
|
|
6
|
-
class Cpus(FactBase):
|
|
7
|
-
|
|
10
|
+
class Cpus(FactBase[int]):
|
|
11
|
+
"""
|
|
8
12
|
Returns the number of CPUs on this server.
|
|
9
|
-
|
|
13
|
+
"""
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
@override
|
|
16
|
+
def command(self) -> str:
|
|
17
|
+
return "getconf NPROCESSORS_ONLN 2> /dev/null || getconf _NPROCESSORS_ONLN"
|
|
12
18
|
|
|
13
|
-
@
|
|
14
|
-
def process(output):
|
|
19
|
+
@override
|
|
20
|
+
def process(self, output):
|
|
15
21
|
try:
|
|
16
|
-
return int(output[0])
|
|
22
|
+
return int(list(output)[0])
|
|
17
23
|
except ValueError:
|
|
18
24
|
pass
|
|
19
25
|
|
|
20
26
|
|
|
21
27
|
class Memory(FactBase):
|
|
22
|
-
|
|
28
|
+
"""
|
|
23
29
|
Returns the memory installed in this server, in MB.
|
|
24
|
-
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
@override
|
|
33
|
+
def requires_command(self) -> str:
|
|
34
|
+
return "vmstat"
|
|
25
35
|
|
|
26
|
-
|
|
36
|
+
@override
|
|
37
|
+
def command(self) -> str:
|
|
38
|
+
return "vmstat -s"
|
|
27
39
|
|
|
28
|
-
@
|
|
29
|
-
def process(output):
|
|
40
|
+
@override
|
|
41
|
+
def process(self, output):
|
|
30
42
|
data = {}
|
|
31
43
|
|
|
32
44
|
for line in output:
|
|
33
|
-
|
|
45
|
+
line = line.strip()
|
|
46
|
+
value, key = line.split(" ", 1)
|
|
34
47
|
|
|
35
48
|
try:
|
|
36
|
-
value =
|
|
49
|
+
value = float(value)
|
|
37
50
|
except ValueError:
|
|
38
51
|
continue
|
|
39
52
|
|
|
40
53
|
data[key.strip()] = value
|
|
41
54
|
|
|
42
55
|
# Easy - Linux just gives us the number
|
|
43
|
-
total_memory = data.get(
|
|
56
|
+
total_memory = data.get("K total memory", data.get("total memory"))
|
|
44
57
|
|
|
45
58
|
# BSD - calculate the total from the # pages and the page size
|
|
46
59
|
if not total_memory:
|
|
47
|
-
bytes_per_page = data.get(
|
|
48
|
-
pages_managed = data.get(
|
|
60
|
+
bytes_per_page = data.get("bytes per page")
|
|
61
|
+
pages_managed = data.get("pages managed")
|
|
49
62
|
|
|
50
63
|
if bytes_per_page and pages_managed:
|
|
51
64
|
total_memory = (pages_managed * bytes_per_page) / 1024
|
|
@@ -55,225 +68,358 @@ class Memory(FactBase):
|
|
|
55
68
|
|
|
56
69
|
|
|
57
70
|
class BlockDevices(FactBase):
|
|
58
|
-
|
|
71
|
+
"""
|
|
59
72
|
Returns a dict of (mounted) block devices:
|
|
60
73
|
|
|
61
74
|
.. code:: python
|
|
62
75
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
76
|
+
{
|
|
77
|
+
"/dev/sda1": {
|
|
78
|
+
"available": "39489508",
|
|
79
|
+
"used_percent": "3",
|
|
80
|
+
"mount": "/",
|
|
81
|
+
"used": "836392",
|
|
82
|
+
"blocks": "40325900"
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
"""
|
|
72
86
|
|
|
73
|
-
|
|
74
|
-
regex = r'([a-zA-Z0-9\/\-_]+)\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+([0-9]{1,3})%\s+([a-zA-Z\/0-9\-_]+)' # noqa: E501
|
|
87
|
+
regex = r"([a-zA-Z0-9\/\-_]+)\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+([0-9]{1,3})%\s+([a-zA-Z\/0-9\-_]+)" # noqa: E501
|
|
75
88
|
default = dict
|
|
76
89
|
|
|
90
|
+
@override
|
|
91
|
+
def command(self) -> str:
|
|
92
|
+
return "df"
|
|
93
|
+
|
|
94
|
+
@override
|
|
77
95
|
def process(self, output):
|
|
78
96
|
devices = {}
|
|
79
97
|
|
|
80
98
|
for line in output:
|
|
81
99
|
matches = re.match(self.regex, line)
|
|
82
100
|
if matches:
|
|
83
|
-
if matches.group(1) ==
|
|
101
|
+
if matches.group(1) == "none":
|
|
84
102
|
continue
|
|
85
103
|
|
|
86
104
|
devices[matches.group(1)] = {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
105
|
+
"blocks": matches.group(2),
|
|
106
|
+
"used": matches.group(3),
|
|
107
|
+
"available": matches.group(4),
|
|
108
|
+
"used_percent": matches.group(5),
|
|
109
|
+
"mount": matches.group(6),
|
|
92
110
|
}
|
|
93
111
|
|
|
94
112
|
return devices
|
|
95
113
|
|
|
96
114
|
|
|
97
|
-
nettools_1_regexes = [
|
|
98
|
-
(
|
|
99
|
-
r'^inet addr:([0-9\.]+).+Bcast:([0-9\.]+).+Mask:([0-9\.]+)$',
|
|
100
|
-
('ipv4', 'address', 'broadcast', 'netmask'),
|
|
101
|
-
),
|
|
102
|
-
(
|
|
103
|
-
r'^inet6 addr: ([0-9a-z:]+)\/([0-9]+) Scope:Global',
|
|
104
|
-
('ipv6', 'address', 'size'), # COMPAT
|
|
105
|
-
# TODO: rename size -> mask_bits (pre-v0.11 compat)
|
|
106
|
-
),
|
|
107
|
-
]
|
|
108
|
-
|
|
109
|
-
nettools_2_regexes = [
|
|
110
|
-
(
|
|
111
|
-
r'^inet ([0-9\.]+)\s+netmask ([0-9\.fx]+)(?:\s+broadcast ([0-9\.]+))?$',
|
|
112
|
-
('ipv4', 'address', 'netmask', 'broadcast'),
|
|
113
|
-
),
|
|
114
|
-
(
|
|
115
|
-
r'^inet6 ([0-9a-z:]+)\s+prefixlen ([0-9]+)',
|
|
116
|
-
('ipv6', 'address', 'size'), # COMPAT
|
|
117
|
-
# TODO: rename size -> mask_bits (pre-v0.11 compat)
|
|
118
|
-
),
|
|
119
|
-
]
|
|
120
|
-
|
|
121
|
-
iproute2_regexes = [
|
|
122
|
-
(
|
|
123
|
-
r'^inet ([0-9\.]+)\/([0-9]{1,2})(?:\s+brd ([0-9\.]+))?',
|
|
124
|
-
('ipv4', 'address', 'mask_bits', 'broadcast'),
|
|
125
|
-
),
|
|
126
|
-
(
|
|
127
|
-
r'^inet6 ([0-9a-z:]+)\/([0-9]{1,3})',
|
|
128
|
-
('ipv6', 'address', 'mask_bits'),
|
|
129
|
-
),
|
|
130
|
-
]
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
def _parse_regexes(regexes, lines):
|
|
134
|
-
data = {
|
|
135
|
-
'ipv4': {},
|
|
136
|
-
'ipv6': {},
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
for line in lines:
|
|
140
|
-
for regex, groups in regexes:
|
|
141
|
-
matches = re.match(regex, line)
|
|
142
|
-
if matches:
|
|
143
|
-
target_group = data[groups[0]]
|
|
144
|
-
|
|
145
|
-
for i, group in enumerate(groups[1:]):
|
|
146
|
-
target_group[group] = matches.group(i + 1)
|
|
147
|
-
|
|
148
|
-
# COMPAT
|
|
149
|
-
# TODO: remove (for forwards compatability, see above)
|
|
150
|
-
if 'size' in target_group:
|
|
151
|
-
target_group['mask_bits'] = target_group['size']
|
|
152
|
-
|
|
153
|
-
if 'mask_bits' in target_group:
|
|
154
|
-
target_group['mask_bits'] = int(target_group['mask_bits'])
|
|
155
|
-
|
|
156
|
-
break
|
|
157
|
-
|
|
158
|
-
return data
|
|
159
|
-
|
|
160
|
-
|
|
161
115
|
class NetworkDevices(FactBase):
|
|
162
|
-
|
|
116
|
+
"""
|
|
163
117
|
Gets & returns a dict of network devices. See the ``ipv4_addresses`` and
|
|
164
118
|
``ipv6_addresses`` facts for easier-to-use shortcuts to get device addresses.
|
|
165
119
|
|
|
166
120
|
.. code:: python
|
|
167
121
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
122
|
+
"enp1s0": {
|
|
123
|
+
"ether": "12:34:56:78:9A:BC",
|
|
124
|
+
"mtu": 1500,
|
|
125
|
+
"state": "UP",
|
|
126
|
+
"ipv4": {
|
|
127
|
+
"address": "192.168.1.100",
|
|
128
|
+
"mask_bits": 24,
|
|
129
|
+
"netmask": "255.255.255.0"
|
|
175
130
|
},
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
131
|
+
"ipv6": {
|
|
132
|
+
"address": "2001:db8:85a3::8a2e:370:7334",
|
|
133
|
+
"mask_bits": 64,
|
|
134
|
+
"additional_ips": [
|
|
135
|
+
{
|
|
136
|
+
"address": "fe80::1234:5678:9abc:def0",
|
|
137
|
+
"mask_bits": 64
|
|
138
|
+
}
|
|
139
|
+
]
|
|
179
140
|
}
|
|
180
141
|
},
|
|
181
|
-
|
|
182
|
-
|
|
142
|
+
"incusbr0": {
|
|
143
|
+
"ether": "DE:AD:BE:EF:CA:FE",
|
|
144
|
+
"mtu": 1500,
|
|
145
|
+
"state": "UP",
|
|
146
|
+
"ipv4": {
|
|
147
|
+
"address": "10.0.0.1",
|
|
148
|
+
"mask_bits": 24,
|
|
149
|
+
"netmask": "255.255.255.0"
|
|
150
|
+
},
|
|
151
|
+
"ipv6": {
|
|
152
|
+
"address": "fe80::dead:beef:cafe:babe",
|
|
153
|
+
"mask_bits": 64,
|
|
154
|
+
"additional_ips": [
|
|
155
|
+
{
|
|
156
|
+
"address": "2001:db8:1234:5678::1",
|
|
157
|
+
"mask_bits": 64
|
|
158
|
+
}
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
"lo": {
|
|
163
|
+
"mtu": 65536,
|
|
164
|
+
"state": "UP",
|
|
165
|
+
"ipv6": {
|
|
166
|
+
"address": "::1",
|
|
167
|
+
"mask_bits": 128
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"veth98806fd6": {
|
|
171
|
+
"ether": "AA:BB:CC:DD:EE:FF",
|
|
172
|
+
"mtu": 1500,
|
|
173
|
+
"state": "UP"
|
|
174
|
+
},
|
|
175
|
+
"vethda29df81": {
|
|
176
|
+
"ether": "11:22:33:44:55:66",
|
|
177
|
+
"mtu": 1500,
|
|
178
|
+
"state": "UP"
|
|
179
|
+
},
|
|
180
|
+
"wlo1": {
|
|
181
|
+
"ether": "77:88:99:AA:BB:CC",
|
|
182
|
+
"mtu": 1500,
|
|
183
|
+
"state": "UNKNOWN"
|
|
184
|
+
}
|
|
185
|
+
"""
|
|
183
186
|
|
|
184
|
-
command = 'ip addr show || ifconfig'
|
|
185
187
|
default = dict
|
|
186
188
|
|
|
189
|
+
@override
|
|
190
|
+
def command(self) -> str:
|
|
191
|
+
return "ip addr show 2> /dev/null || ifconfig -a"
|
|
192
|
+
|
|
187
193
|
# Definition of valid interface names for Linux:
|
|
188
194
|
# https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/net/core/dev.c?h=v5.1.3#n1020
|
|
189
|
-
|
|
190
|
-
(
|
|
191
|
-
r'^([^/: \s]+)\s+Link encap:',
|
|
192
|
-
lambda lines: _parse_regexes(nettools_1_regexes, lines),
|
|
193
|
-
),
|
|
194
|
-
(
|
|
195
|
-
r'^([^/: \s]+): flags=',
|
|
196
|
-
lambda lines: _parse_regexes(nettools_2_regexes, lines),
|
|
197
|
-
),
|
|
198
|
-
(
|
|
199
|
-
r'^[0-9]+: ([^/: \s]+): ',
|
|
200
|
-
lambda lines: _parse_regexes(iproute2_regexes, lines),
|
|
201
|
-
),
|
|
202
|
-
]
|
|
203
|
-
|
|
195
|
+
@override
|
|
204
196
|
def process(self, output):
|
|
205
|
-
|
|
197
|
+
def mask(value):
|
|
198
|
+
try:
|
|
199
|
+
if value.startswith("0x"):
|
|
200
|
+
mask_bits = bin(int(value, 16)).count("1")
|
|
201
|
+
else:
|
|
202
|
+
mask_bits = int(value)
|
|
203
|
+
netmask = ".".join(
|
|
204
|
+
str((0xFFFFFFFF << (32 - b) >> mask_bits) & 0xFF) for b in (24, 16, 8, 0)
|
|
205
|
+
)
|
|
206
|
+
except ValueError:
|
|
207
|
+
mask_bits = sum(bin(int(x)).count("1") for x in value.split("."))
|
|
208
|
+
netmask = value
|
|
206
209
|
|
|
207
|
-
|
|
208
|
-
matches = None
|
|
209
|
-
handler = None
|
|
210
|
-
line_buffer = []
|
|
210
|
+
return mask_bits, netmask
|
|
211
211
|
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
# Strip lines and merge them as a block of text
|
|
213
|
+
output = "\n".join(map(str.strip, output))
|
|
214
214
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
new_matches = re.match(regex, line)
|
|
215
|
+
# Splitting the output into sections per network device
|
|
216
|
+
device_sections = re.split(r"\n(?=\d+: [^\s/:]|[^\s/:]+:.*mtu )", output)
|
|
218
217
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
matched = True
|
|
218
|
+
# Dictionary to hold all device information
|
|
219
|
+
all_devices = {}
|
|
222
220
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
221
|
+
for section in device_sections:
|
|
222
|
+
# Extracting the device name
|
|
223
|
+
device_name_match = re.match(r"^(?:\d+: )?([^\s/:]+):", section)
|
|
224
|
+
if not device_name_match:
|
|
225
|
+
continue
|
|
226
|
+
device_name = device_name_match.group(1)
|
|
227
|
+
|
|
228
|
+
# Regular expressions to match different parts of the output
|
|
229
|
+
ether_re = re.compile(r"ether ([0-9A-Fa-f:]{17})")
|
|
230
|
+
mtu_re = re.compile(r"mtu (\d+)")
|
|
231
|
+
ipv4_re = (
|
|
232
|
+
# ip a
|
|
233
|
+
re.compile(
|
|
234
|
+
r"inet (?P<address>\d+\.\d+\.\d+\.\d+)/(?P<mask>\d+)(?: metric \d+)?(?: brd (?P<broadcast>\d+\.\d+\.\d+\.\d+))?" # noqa: E501
|
|
235
|
+
),
|
|
236
|
+
# ifconfig -a
|
|
237
|
+
re.compile(
|
|
238
|
+
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
|
|
239
|
+
),
|
|
240
|
+
)
|
|
241
|
+
ipv6_re = (
|
|
242
|
+
# ip a
|
|
243
|
+
re.compile(r"inet6\s+(?P<address>[0-9a-fA-F:]+)/(?P<mask>\d+)"),
|
|
244
|
+
# ifconfig -a
|
|
245
|
+
re.compile(r"inet6\s+(?P<address>[0-9a-fA-F:]+)\s+prefixlen\s+(?P<mask>\d+)"),
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
# Parsing the output
|
|
249
|
+
ether = ether_re.search(section)
|
|
250
|
+
mtu = mtu_re.search(section)
|
|
251
|
+
|
|
252
|
+
# Building the result dictionary for the device
|
|
253
|
+
device_info = {}
|
|
254
|
+
if ether:
|
|
255
|
+
device_info["ether"] = ether.group(1)
|
|
256
|
+
if mtu:
|
|
257
|
+
device_info["mtu"] = int(mtu.group(1))
|
|
258
|
+
|
|
259
|
+
device_info["state"] = (
|
|
260
|
+
"UP" if "UP" in section else "DOWN" if "DOWN" in section else "UNKNOWN"
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
# IPv4 Addresses
|
|
264
|
+
ipv4_matches: list[re.Match[str]]
|
|
265
|
+
for ipv4_re_ in ipv4_re:
|
|
266
|
+
ipv4_matches = list(ipv4_re_.finditer(section))
|
|
267
|
+
if len(ipv4_matches):
|
|
268
|
+
break
|
|
227
269
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
270
|
+
if len(ipv4_matches):
|
|
271
|
+
ipv4_info = []
|
|
272
|
+
for ipv4 in ipv4_matches:
|
|
273
|
+
address = ipv4.group("address")
|
|
274
|
+
mask_value = ipv4.group("mask")
|
|
275
|
+
mask_bits, netmask = mask(mask_value)
|
|
276
|
+
try:
|
|
277
|
+
broadcast = ipv4.group("broadcast")
|
|
278
|
+
except IndexError:
|
|
279
|
+
broadcast = None
|
|
280
|
+
|
|
281
|
+
ipv4_info.append(
|
|
282
|
+
{
|
|
283
|
+
"address": address,
|
|
284
|
+
"mask_bits": mask_bits,
|
|
285
|
+
"netmask": netmask,
|
|
286
|
+
"broadcast": broadcast,
|
|
287
|
+
},
|
|
288
|
+
)
|
|
289
|
+
device_info["ipv4"] = ipv4_info[0]
|
|
290
|
+
if len(ipv4_matches) > 1:
|
|
291
|
+
device_info["ipv4"]["additional_ips"] = ipv4_info[1:] # type: ignore[index]
|
|
292
|
+
|
|
293
|
+
# IPv6 Addresses
|
|
294
|
+
ipv6_matches: list[re.Match[str]]
|
|
295
|
+
for ipv6_re_ in ipv6_re:
|
|
296
|
+
ipv6_matches = list(ipv6_re_.finditer(section))
|
|
297
|
+
if ipv6_matches:
|
|
231
298
|
break
|
|
232
299
|
|
|
233
|
-
if
|
|
234
|
-
|
|
300
|
+
if len(ipv6_matches):
|
|
301
|
+
ipv6_info = []
|
|
302
|
+
for ipv6 in ipv6_matches:
|
|
303
|
+
address = ipv6.group("address")
|
|
304
|
+
mask_bits = ipv6.group("mask")
|
|
305
|
+
ipv6_info.append({"address": address, "mask_bits": int(mask_bits)})
|
|
306
|
+
device_info["ipv6"] = ipv6_info[0]
|
|
307
|
+
if len(ipv6_matches) > 1:
|
|
308
|
+
device_info["ipv6"]["additional_ips"] = ipv6_info[1:] # type: ignore[index]
|
|
235
309
|
|
|
236
|
-
|
|
237
|
-
if matches:
|
|
238
|
-
devices[matches.group(1)] = handler(line_buffer)
|
|
310
|
+
all_devices[device_name] = device_info
|
|
239
311
|
|
|
240
|
-
return
|
|
312
|
+
return all_devices
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
class Ipv4Addrs(ShortFactBase):
|
|
316
|
+
"""
|
|
317
|
+
Gets & returns a dictionary of network interface -> list of IPv4 addresses.
|
|
318
|
+
|
|
319
|
+
.. code:: python
|
|
320
|
+
|
|
321
|
+
{
|
|
322
|
+
"eth0": ["127.0.0.1"],
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.. note::
|
|
326
|
+
Network interfaces with no IPv4 will not be part of the dictionary.
|
|
327
|
+
"""
|
|
328
|
+
|
|
329
|
+
fact = NetworkDevices
|
|
330
|
+
ip_type = "ipv4"
|
|
331
|
+
|
|
332
|
+
@override
|
|
333
|
+
def process_data(self, data):
|
|
334
|
+
host_to_ips = {}
|
|
335
|
+
|
|
336
|
+
for interface, details in data.items():
|
|
337
|
+
ips = []
|
|
338
|
+
|
|
339
|
+
ip_details = details.get(self.ip_type)
|
|
340
|
+
if not ip_details or not ip_details.get("address"):
|
|
341
|
+
continue
|
|
342
|
+
|
|
343
|
+
ips.append(ip_details["address"])
|
|
344
|
+
if "additional_ips" in ip_details:
|
|
345
|
+
ips.extend([ip["address"] for ip in ip_details["additional_ips"]])
|
|
346
|
+
|
|
347
|
+
host_to_ips[interface] = ips
|
|
348
|
+
|
|
349
|
+
return host_to_ips
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
class Ipv6Addrs(Ipv4Addrs):
|
|
353
|
+
"""
|
|
354
|
+
Gets & returns a dictionary of network interface -> list of IPv6 addresses.
|
|
355
|
+
|
|
356
|
+
.. code:: python
|
|
357
|
+
|
|
358
|
+
{
|
|
359
|
+
"eth0": ["fe80::a00:27ff::2"],
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.. note::
|
|
363
|
+
Network interfaces with no IPv6 will not be part of the dictionary.
|
|
364
|
+
"""
|
|
365
|
+
|
|
366
|
+
ip_type = "ipv6"
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
# TODO: remove these in v3
|
|
370
|
+
# Legacy versions of the above that only support one IP per interface
|
|
371
|
+
#
|
|
241
372
|
|
|
242
373
|
|
|
243
374
|
class Ipv4Addresses(ShortFactBase):
|
|
244
|
-
|
|
375
|
+
"""
|
|
245
376
|
Gets & returns a dictionary of network interface -> IPv4 address.
|
|
246
377
|
|
|
247
378
|
.. code:: python
|
|
248
379
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
380
|
+
{
|
|
381
|
+
"eth0": "127.0.0.1",
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.. warning::
|
|
385
|
+
This fact is deprecated, please use the ``hardware.Ipv4Addrs`` fact.
|
|
386
|
+
|
|
387
|
+
.. note::
|
|
388
|
+
Network interfaces with no IPv4 will not be part of the dictionary.
|
|
389
|
+
"""
|
|
252
390
|
|
|
253
391
|
fact = NetworkDevices
|
|
254
|
-
ip_type =
|
|
392
|
+
ip_type = "ipv4"
|
|
255
393
|
|
|
394
|
+
@override
|
|
256
395
|
def process_data(self, data):
|
|
257
396
|
addresses = {}
|
|
258
397
|
|
|
259
398
|
for interface, details in data.items():
|
|
260
399
|
ip_details = details.get(self.ip_type)
|
|
261
|
-
if not ip_details:
|
|
262
|
-
continue #
|
|
400
|
+
if not ip_details or not ip_details.get("address"):
|
|
401
|
+
continue # pragma: no cover
|
|
263
402
|
|
|
264
|
-
addresses[interface] = ip_details[
|
|
403
|
+
addresses[interface] = ip_details["address"]
|
|
265
404
|
|
|
266
405
|
return addresses
|
|
267
406
|
|
|
268
407
|
|
|
269
408
|
class Ipv6Addresses(Ipv4Addresses):
|
|
270
|
-
|
|
409
|
+
"""
|
|
271
410
|
Gets & returns a dictionary of network interface -> IPv6 address.
|
|
272
411
|
|
|
273
412
|
.. code:: python
|
|
274
413
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
414
|
+
{
|
|
415
|
+
"eth0": "fe80::a00:27ff::2",
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.. warning::
|
|
419
|
+
This fact is deprecated, please use the ``hardware.Ipv6Addrs`` fact.
|
|
420
|
+
|
|
421
|
+
.. note::
|
|
422
|
+
Network interfaces with no IPv6 will not be part of the dictionary.
|
|
423
|
+
"""
|
|
278
424
|
|
|
279
|
-
ip_type =
|
|
425
|
+
ip_type = "ipv6"
|