pyinfra 3.2__py2.py3-none-any.whl → 3.3.1__py2.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/api/arguments_typed.py +4 -5
- pyinfra/api/command.py +22 -3
- pyinfra/api/config.py +5 -2
- pyinfra/api/facts.py +3 -0
- pyinfra/api/host.py +10 -4
- pyinfra/api/operation.py +2 -1
- pyinfra/api/state.py +1 -1
- pyinfra/connectors/base.py +34 -8
- pyinfra/connectors/chroot.py +7 -2
- pyinfra/connectors/docker.py +7 -2
- pyinfra/connectors/dockerssh.py +7 -2
- pyinfra/connectors/local.py +7 -2
- pyinfra/connectors/ssh.py +9 -2
- pyinfra/connectors/sshuserclient/client.py +18 -2
- pyinfra/connectors/sshuserclient/config.py +2 -0
- pyinfra/connectors/terraform.py +1 -1
- pyinfra/connectors/util.py +13 -9
- pyinfra/context.py +9 -2
- pyinfra/facts/apk.py +5 -0
- pyinfra/facts/apt.py +9 -1
- pyinfra/facts/brew.py +13 -0
- pyinfra/facts/bsdinit.py +3 -0
- pyinfra/facts/cargo.py +5 -0
- pyinfra/facts/choco.py +6 -0
- pyinfra/facts/crontab.py +6 -1
- pyinfra/facts/deb.py +10 -0
- pyinfra/facts/dnf.py +5 -0
- pyinfra/facts/docker.py +10 -0
- pyinfra/facts/efibootmgr.py +5 -0
- pyinfra/facts/files.py +19 -1
- pyinfra/facts/flatpak.py +7 -0
- pyinfra/facts/freebsd.py +75 -0
- pyinfra/facts/gem.py +5 -0
- pyinfra/facts/git.py +9 -0
- pyinfra/facts/gpg.py +7 -0
- pyinfra/facts/hardware.py +13 -0
- pyinfra/facts/iptables.py +9 -1
- pyinfra/facts/launchd.py +5 -0
- pyinfra/facts/lxd.py +5 -0
- pyinfra/facts/mysql.py +8 -0
- pyinfra/facts/npm.py +5 -0
- pyinfra/facts/openrc.py +8 -0
- pyinfra/facts/opkg.py +12 -0
- pyinfra/facts/pacman.py +9 -1
- pyinfra/facts/pip.py +5 -0
- pyinfra/facts/pipx.py +8 -0
- pyinfra/facts/pkg.py +4 -0
- pyinfra/facts/pkgin.py +5 -0
- pyinfra/facts/podman.py +7 -0
- pyinfra/facts/postgres.py +8 -2
- pyinfra/facts/rpm.py +11 -0
- pyinfra/facts/runit.py +7 -0
- pyinfra/facts/selinux.py +16 -0
- pyinfra/facts/server.py +49 -3
- pyinfra/facts/snap.py +7 -0
- pyinfra/facts/systemd.py +5 -0
- pyinfra/facts/sysvinit.py +4 -0
- pyinfra/facts/upstart.py +5 -0
- pyinfra/facts/util/__init__.py +4 -1
- pyinfra/facts/vzctl.py +5 -0
- pyinfra/facts/xbps.py +6 -1
- pyinfra/facts/yum.py +5 -0
- pyinfra/facts/zfs.py +19 -2
- pyinfra/facts/zypper.py +5 -0
- pyinfra/operations/apt.py +10 -3
- pyinfra/operations/docker.py +48 -44
- pyinfra/operations/files.py +47 -1
- 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/opkg.py +5 -5
- pyinfra/operations/postgres.py +99 -16
- pyinfra/operations/server.py +6 -4
- pyinfra/operations/util/docker.py +44 -22
- {pyinfra-3.2.dist-info → pyinfra-3.3.1.dist-info}/LICENSE.md +1 -1
- {pyinfra-3.2.dist-info → pyinfra-3.3.1.dist-info}/METADATA +25 -24
- {pyinfra-3.2.dist-info → pyinfra-3.3.1.dist-info}/RECORD +89 -83
- pyinfra_cli/exceptions.py +5 -0
- pyinfra_cli/log.py +3 -0
- pyinfra_cli/main.py +9 -8
- pyinfra_cli/prints.py +1 -1
- pyinfra_cli/virtualenv.py +1 -1
- tests/test_connectors/test_ssh.py +302 -182
- tests/test_connectors/test_sshuserclient.py +10 -5
- {pyinfra-3.2.dist-info → pyinfra-3.3.1.dist-info}/WHEEL +0 -0
- {pyinfra-3.2.dist-info → pyinfra-3.3.1.dist-info}/entry_points.txt +0 -0
- {pyinfra-3.2.dist-info → pyinfra-3.3.1.dist-info}/top_level.txt +0 -0
pyinfra/facts/opkg.py
CHANGED
|
@@ -12,6 +12,8 @@ Gather the information provided by ``opkg`` on OpenWrt systems:
|
|
|
12
12
|
import re
|
|
13
13
|
from typing import Dict, NamedTuple, Union
|
|
14
14
|
|
|
15
|
+
from typing_extensions import override
|
|
16
|
+
|
|
15
17
|
from pyinfra import logger
|
|
16
18
|
from pyinfra.api import FactBase
|
|
17
19
|
from pyinfra.facts.util.packaging import parse_packages
|
|
@@ -83,9 +85,11 @@ class OpkgConf(FactBase):
|
|
|
83
85
|
def default():
|
|
84
86
|
return OpkgConfInfo({}, "", {}, {})
|
|
85
87
|
|
|
88
|
+
@override
|
|
86
89
|
def command(self) -> str:
|
|
87
90
|
return "cat /etc/opkg.conf"
|
|
88
91
|
|
|
92
|
+
@override
|
|
89
93
|
def process(self, output):
|
|
90
94
|
dest, lists_dir, options, arch_cfg = {}, "", {}, {}
|
|
91
95
|
for line in output:
|
|
@@ -127,9 +131,11 @@ class OpkgFeeds(FactBase):
|
|
|
127
131
|
)
|
|
128
132
|
default = dict
|
|
129
133
|
|
|
134
|
+
@override
|
|
130
135
|
def command(self) -> str:
|
|
131
136
|
return "cat /etc/opkg/distfeeds.conf; echo CUSTOM; cat /etc/opkg/customfeeds.conf"
|
|
132
137
|
|
|
138
|
+
@override
|
|
133
139
|
def process(self, output):
|
|
134
140
|
feeds, kind = {}, "distribution"
|
|
135
141
|
for line in output:
|
|
@@ -164,9 +170,11 @@ class OpkgInstallableArchitectures(FactBase):
|
|
|
164
170
|
regex = re.compile(r"^(?:\s*arch\s+(?P<arch>[\w]+)\s+(?P<prio>\d+))?(\s*#.*)?$")
|
|
165
171
|
default = dict
|
|
166
172
|
|
|
173
|
+
@override
|
|
167
174
|
def command(self) -> str:
|
|
168
175
|
return "/bin/opkg print-architecture"
|
|
169
176
|
|
|
177
|
+
@override
|
|
170
178
|
def process(self, output):
|
|
171
179
|
arch_list = {}
|
|
172
180
|
for line in output:
|
|
@@ -195,9 +203,11 @@ class OpkgPackages(FactBase):
|
|
|
195
203
|
regex = r"^([a-zA-Z0-9][\w\-\.]*)\s-\s([\w\-\.]+)"
|
|
196
204
|
default = dict
|
|
197
205
|
|
|
206
|
+
@override
|
|
198
207
|
def command(self) -> str:
|
|
199
208
|
return "/bin/opkg list-installed"
|
|
200
209
|
|
|
210
|
+
@override
|
|
201
211
|
def process(self, output):
|
|
202
212
|
return parse_packages(self.regex, sorted(output))
|
|
203
213
|
|
|
@@ -218,9 +228,11 @@ class OpkgUpgradeablePackages(FactBase):
|
|
|
218
228
|
default = dict
|
|
219
229
|
use_default_on_error = True
|
|
220
230
|
|
|
231
|
+
@override
|
|
221
232
|
def command(self) -> str:
|
|
222
233
|
return "/bin/opkg list-upgradable" # yes, really spelled that way
|
|
223
234
|
|
|
235
|
+
@override
|
|
224
236
|
def process(self, output):
|
|
225
237
|
result = {}
|
|
226
238
|
for line in output:
|
pyinfra/facts/pacman.py
CHANGED
|
@@ -2,11 +2,13 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import shlex
|
|
4
4
|
|
|
5
|
+
from typing_extensions import override
|
|
6
|
+
|
|
5
7
|
from pyinfra.api import FactBase
|
|
6
8
|
|
|
7
9
|
from .util.packaging import parse_packages
|
|
8
10
|
|
|
9
|
-
PACMAN_REGEX = r"^([0-9a-zA-Z\-]+)\s([0-9\._+a-z
|
|
11
|
+
PACMAN_REGEX = r"^([0-9a-zA-Z\-_]+)\s([0-9\._+a-z\-:]+)"
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
class PacmanUnpackGroup(FactBase):
|
|
@@ -21,15 +23,18 @@ class PacmanUnpackGroup(FactBase):
|
|
|
21
23
|
]
|
|
22
24
|
"""
|
|
23
25
|
|
|
26
|
+
@override
|
|
24
27
|
def requires_command(self, *args, **kwargs) -> str:
|
|
25
28
|
return "pacman"
|
|
26
29
|
|
|
27
30
|
default = list
|
|
28
31
|
|
|
32
|
+
@override
|
|
29
33
|
def command(self, package):
|
|
30
34
|
# Accept failure here (|| true) for invalid/unknown packages
|
|
31
35
|
return 'pacman -S --print-format "%n" {0} || true'.format(shlex.quote(package))
|
|
32
36
|
|
|
37
|
+
@override
|
|
33
38
|
def process(self, output):
|
|
34
39
|
return output
|
|
35
40
|
|
|
@@ -45,13 +50,16 @@ class PacmanPackages(FactBase):
|
|
|
45
50
|
}
|
|
46
51
|
"""
|
|
47
52
|
|
|
53
|
+
@override
|
|
48
54
|
def command(self) -> str:
|
|
49
55
|
return "pacman -Q"
|
|
50
56
|
|
|
57
|
+
@override
|
|
51
58
|
def requires_command(self, *args, **kwargs) -> str:
|
|
52
59
|
return "pacman"
|
|
53
60
|
|
|
54
61
|
default = dict
|
|
55
62
|
|
|
63
|
+
@override
|
|
56
64
|
def process(self, output):
|
|
57
65
|
return parse_packages(PACMAN_REGEX, output)
|
pyinfra/facts/pip.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing_extensions import override
|
|
4
|
+
|
|
3
5
|
from pyinfra.api import FactBase
|
|
4
6
|
|
|
5
7
|
from .util.packaging import parse_packages
|
|
@@ -21,13 +23,16 @@ class PipPackages(FactBase):
|
|
|
21
23
|
default = dict
|
|
22
24
|
pip_command = "pip"
|
|
23
25
|
|
|
26
|
+
@override
|
|
24
27
|
def requires_command(self, pip=None):
|
|
25
28
|
return pip or self.pip_command
|
|
26
29
|
|
|
30
|
+
@override
|
|
27
31
|
def command(self, pip=None):
|
|
28
32
|
pip = pip or self.pip_command
|
|
29
33
|
return "{0} freeze --all".format(pip)
|
|
30
34
|
|
|
35
|
+
@override
|
|
31
36
|
def process(self, output):
|
|
32
37
|
return parse_packages(PIP_REGEX, output)
|
|
33
38
|
|
pyinfra/facts/pipx.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import re
|
|
2
2
|
|
|
3
|
+
from typing_extensions import override
|
|
4
|
+
|
|
3
5
|
from pyinfra.api import FactBase
|
|
4
6
|
|
|
5
7
|
from .util.packaging import parse_packages
|
|
@@ -35,12 +37,15 @@ class PipxPackages(FactBase):
|
|
|
35
37
|
|
|
36
38
|
default = dict
|
|
37
39
|
|
|
40
|
+
@override
|
|
38
41
|
def requires_command(self) -> str:
|
|
39
42
|
return "pipx"
|
|
40
43
|
|
|
44
|
+
@override
|
|
41
45
|
def command(self) -> str:
|
|
42
46
|
return "pipx list --short"
|
|
43
47
|
|
|
48
|
+
@override
|
|
44
49
|
def process(self, output):
|
|
45
50
|
return parse_packages(PIPX_REGEX, output)
|
|
46
51
|
|
|
@@ -64,11 +69,14 @@ class PipxEnvironment(FactBase):
|
|
|
64
69
|
|
|
65
70
|
default = dict
|
|
66
71
|
|
|
72
|
+
@override
|
|
67
73
|
def requires_command(self) -> str:
|
|
68
74
|
return "pipx"
|
|
69
75
|
|
|
76
|
+
@override
|
|
70
77
|
def command(self) -> str:
|
|
71
78
|
return "pipx environment"
|
|
72
79
|
|
|
80
|
+
@override
|
|
73
81
|
def process(self, output):
|
|
74
82
|
return parse_environment(output)
|
pyinfra/facts/pkg.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing_extensions import override
|
|
4
|
+
|
|
3
5
|
from pyinfra.api import FactBase
|
|
4
6
|
|
|
5
7
|
from .util.packaging import parse_packages
|
|
@@ -19,8 +21,10 @@ class PkgPackages(FactBase):
|
|
|
19
21
|
regex = r"^([a-zA-Z0-9_\-\+]+)\-([0-9a-z\.]+)"
|
|
20
22
|
default = dict
|
|
21
23
|
|
|
24
|
+
@override
|
|
22
25
|
def command(self) -> str:
|
|
23
26
|
return "pkg info || pkg_info || true"
|
|
24
27
|
|
|
28
|
+
@override
|
|
25
29
|
def process(self, output):
|
|
26
30
|
return parse_packages(self.regex, output)
|
pyinfra/facts/pkgin.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing_extensions import override
|
|
4
|
+
|
|
3
5
|
from pyinfra.api import FactBase
|
|
4
6
|
|
|
5
7
|
from .util.packaging import parse_packages
|
|
@@ -18,13 +20,16 @@ class PkginPackages(FactBase):
|
|
|
18
20
|
}
|
|
19
21
|
"""
|
|
20
22
|
|
|
23
|
+
@override
|
|
21
24
|
def command(self) -> str:
|
|
22
25
|
return "pkgin list"
|
|
23
26
|
|
|
27
|
+
@override
|
|
24
28
|
def requires_command(self) -> str:
|
|
25
29
|
return "pkgin"
|
|
26
30
|
|
|
27
31
|
default = dict
|
|
28
32
|
|
|
33
|
+
@override
|
|
29
34
|
def process(self, output):
|
|
30
35
|
return parse_packages(PKGIN_REGEX, output)
|
pyinfra/facts/podman.py
CHANGED
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import json
|
|
4
4
|
from typing import Any, Dict, Iterable, List, TypeVar
|
|
5
5
|
|
|
6
|
+
from typing_extensions import override
|
|
7
|
+
|
|
6
8
|
from pyinfra.api import FactBase
|
|
7
9
|
|
|
8
10
|
T = TypeVar("T")
|
|
@@ -15,6 +17,7 @@ class PodmanFactBase(FactBase[T]):
|
|
|
15
17
|
|
|
16
18
|
abstract = True
|
|
17
19
|
|
|
20
|
+
@override
|
|
18
21
|
def requires_command(self, *args, **kwargs) -> str:
|
|
19
22
|
return "podman"
|
|
20
23
|
|
|
@@ -24,9 +27,11 @@ class PodmanSystemInfo(PodmanFactBase[Dict[str, Any]]):
|
|
|
24
27
|
Output of 'podman system info'
|
|
25
28
|
"""
|
|
26
29
|
|
|
30
|
+
@override
|
|
27
31
|
def command(self) -> str:
|
|
28
32
|
return "podman system info --format=json"
|
|
29
33
|
|
|
34
|
+
@override
|
|
30
35
|
def process(self, output: Iterable[str]) -> Dict[str, Any]:
|
|
31
36
|
output = json.loads(("").join(output))
|
|
32
37
|
assert isinstance(output, dict)
|
|
@@ -38,9 +43,11 @@ class PodmanPs(PodmanFactBase[List[Dict[str, Any]]]):
|
|
|
38
43
|
Output of 'podman ps'
|
|
39
44
|
"""
|
|
40
45
|
|
|
46
|
+
@override
|
|
41
47
|
def command(self) -> str:
|
|
42
48
|
return "podman ps --format=json --all"
|
|
43
49
|
|
|
50
|
+
@override
|
|
44
51
|
def process(self, output: Iterable[str]) -> List[Dict[str, Any]]:
|
|
45
52
|
output = json.loads(("").join(output))
|
|
46
53
|
assert isinstance(output, list)
|
pyinfra/facts/postgres.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from typing_extensions import override
|
|
4
|
+
|
|
3
5
|
from pyinfra.api import FactBase, MaskString, QuoteString, StringCommand
|
|
4
6
|
from pyinfra.api.util import try_int
|
|
5
7
|
|
|
@@ -49,9 +51,11 @@ class PostgresFactBase(FactBase):
|
|
|
49
51
|
|
|
50
52
|
psql_command: str
|
|
51
53
|
|
|
54
|
+
@override
|
|
52
55
|
def requires_command(self, *args, **kwargs):
|
|
53
56
|
return "psql"
|
|
54
57
|
|
|
58
|
+
@override
|
|
55
59
|
def command(
|
|
56
60
|
self,
|
|
57
61
|
psql_user=None,
|
|
@@ -89,6 +93,7 @@ class PostgresRoles(PostgresFactBase):
|
|
|
89
93
|
default = dict
|
|
90
94
|
psql_command = "SELECT * FROM pg_catalog.pg_roles"
|
|
91
95
|
|
|
96
|
+
@override
|
|
92
97
|
def process(self, output):
|
|
93
98
|
# Remove the last line of the output (row count)
|
|
94
99
|
output = output[:-1]
|
|
@@ -139,8 +144,9 @@ class PostgresDatabases(PostgresFactBase):
|
|
|
139
144
|
"""
|
|
140
145
|
|
|
141
146
|
default = dict
|
|
142
|
-
psql_command = "SELECT pg_catalog.pg_encoding_to_char(encoding),
|
|
147
|
+
psql_command = "SELECT pg_catalog.pg_encoding_to_char(encoding), *, pg_catalog.pg_get_userbyid(datdba) AS owner FROM pg_catalog.pg_database" # noqa: E501
|
|
143
148
|
|
|
149
|
+
@override
|
|
144
150
|
def process(self, output):
|
|
145
151
|
# Remove the last line of the output (row count)
|
|
146
152
|
output = output[:-1]
|
|
@@ -155,7 +161,7 @@ class PostgresDatabases(PostgresFactBase):
|
|
|
155
161
|
|
|
156
162
|
for details in rows:
|
|
157
163
|
details["encoding"] = details.pop("pg_encoding_to_char")
|
|
158
|
-
|
|
164
|
+
details["owner"] = details.pop("owner")
|
|
159
165
|
for key, value in list(details.items()):
|
|
160
166
|
if key.endswith("id") or key in (
|
|
161
167
|
"dba",
|
pyinfra/facts/rpm.py
CHANGED
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import re
|
|
4
4
|
import shlex
|
|
5
5
|
|
|
6
|
+
from typing_extensions import override
|
|
7
|
+
|
|
6
8
|
from pyinfra.api import FactBase
|
|
7
9
|
|
|
8
10
|
from .util.packaging import parse_packages
|
|
@@ -22,14 +24,17 @@ class RpmPackages(FactBase):
|
|
|
22
24
|
}
|
|
23
25
|
"""
|
|
24
26
|
|
|
27
|
+
@override
|
|
25
28
|
def command(self) -> str:
|
|
26
29
|
return "rpm --queryformat {0} -qa".format(shlex.quote(rpm_query_format))
|
|
27
30
|
|
|
31
|
+
@override
|
|
28
32
|
def requires_command(self) -> str:
|
|
29
33
|
return "rpm"
|
|
30
34
|
|
|
31
35
|
default = dict
|
|
32
36
|
|
|
37
|
+
@override
|
|
33
38
|
def process(self, output):
|
|
34
39
|
return parse_packages(rpm_regex, output)
|
|
35
40
|
|
|
@@ -46,9 +51,11 @@ class RpmPackage(FactBase):
|
|
|
46
51
|
}
|
|
47
52
|
"""
|
|
48
53
|
|
|
54
|
+
@override
|
|
49
55
|
def requires_command(self, package) -> str:
|
|
50
56
|
return "rpm"
|
|
51
57
|
|
|
58
|
+
@override
|
|
52
59
|
def command(self, package) -> str:
|
|
53
60
|
return (
|
|
54
61
|
"rpm --queryformat {0} -q {1} || "
|
|
@@ -56,6 +63,7 @@ class RpmPackage(FactBase):
|
|
|
56
63
|
"rpm --queryformat {0} -qp {1} 2> /dev/null"
|
|
57
64
|
).format(shlex.quote(rpm_query_format), shlex.quote(package))
|
|
58
65
|
|
|
66
|
+
@override
|
|
59
67
|
def process(self, output):
|
|
60
68
|
for line in output:
|
|
61
69
|
matches = re.match(rpm_regex, line)
|
|
@@ -73,9 +81,11 @@ class RpmPackageProvides(FactBase):
|
|
|
73
81
|
|
|
74
82
|
default = list
|
|
75
83
|
|
|
84
|
+
@override
|
|
76
85
|
def requires_command(self, *args, **kwargs) -> str:
|
|
77
86
|
return "repoquery"
|
|
78
87
|
|
|
88
|
+
@override
|
|
79
89
|
def command(self, package):
|
|
80
90
|
# Accept failure here (|| true) for invalid/unknown packages
|
|
81
91
|
return "repoquery --queryformat {0} --whatprovides {1} || true".format(
|
|
@@ -83,6 +93,7 @@ class RpmPackageProvides(FactBase):
|
|
|
83
93
|
shlex.quote(package),
|
|
84
94
|
)
|
|
85
95
|
|
|
96
|
+
@override
|
|
86
97
|
def process(self, output):
|
|
87
98
|
packages = []
|
|
88
99
|
|
pyinfra/facts/runit.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from typing_extensions import override
|
|
2
|
+
|
|
1
3
|
from pyinfra.api import FactBase
|
|
2
4
|
|
|
3
5
|
|
|
@@ -20,9 +22,11 @@ class RunitStatus(FactBase):
|
|
|
20
22
|
|
|
21
23
|
default = dict
|
|
22
24
|
|
|
25
|
+
@override
|
|
23
26
|
def requires_command(self, *args, **kwargs) -> str:
|
|
24
27
|
return "sv"
|
|
25
28
|
|
|
29
|
+
@override
|
|
26
30
|
def command(self, service=None, svdir="/var/service") -> str:
|
|
27
31
|
if service is None:
|
|
28
32
|
return (
|
|
@@ -32,6 +36,7 @@ class RunitStatus(FactBase):
|
|
|
32
36
|
else:
|
|
33
37
|
return 'SVDIR="{0}" sv status "{1}"'.format(svdir, service)
|
|
34
38
|
|
|
39
|
+
@override
|
|
35
40
|
def process(self, output):
|
|
36
41
|
services = {}
|
|
37
42
|
for line in output:
|
|
@@ -60,11 +65,13 @@ class RunitManaged(FactBase):
|
|
|
60
65
|
|
|
61
66
|
default = set
|
|
62
67
|
|
|
68
|
+
@override
|
|
63
69
|
def command(self, service=None, svdir="/var/service"):
|
|
64
70
|
if service is None:
|
|
65
71
|
return 'cd "{0}" && find -mindepth 1 -maxdepth 1 -type l -printf "%f\n"'.format(svdir)
|
|
66
72
|
else:
|
|
67
73
|
return 'cd "{0}" && test -h "{1}" && echo "{1}" || true'.format(svdir, service)
|
|
68
74
|
|
|
75
|
+
@override
|
|
69
76
|
def process(self, output):
|
|
70
77
|
return set(output)
|
pyinfra/facts/selinux.py
CHANGED
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import re
|
|
4
4
|
from collections import defaultdict
|
|
5
5
|
|
|
6
|
+
from typing_extensions import override
|
|
7
|
+
|
|
6
8
|
from pyinfra.api import FactBase
|
|
7
9
|
|
|
8
10
|
FIELDS = ["user", "role", "type", "level"] # order is significant, do not change
|
|
@@ -14,14 +16,17 @@ class SEBoolean(FactBase):
|
|
|
14
16
|
If ``boolean`` does not exist, ``SEBoolean`` returns the empty string.
|
|
15
17
|
"""
|
|
16
18
|
|
|
19
|
+
@override
|
|
17
20
|
def requires_command(self, boolean) -> str:
|
|
18
21
|
return "getsebool"
|
|
19
22
|
|
|
20
23
|
default = str
|
|
21
24
|
|
|
25
|
+
@override
|
|
22
26
|
def command(self, boolean):
|
|
23
27
|
return "getsebool {0}".format(boolean)
|
|
24
28
|
|
|
29
|
+
@override
|
|
25
30
|
def process(self, output):
|
|
26
31
|
components = output[0].split(" --> ")
|
|
27
32
|
return components[1]
|
|
@@ -42,9 +47,11 @@ class FileContext(FactBase):
|
|
|
42
47
|
}
|
|
43
48
|
"""
|
|
44
49
|
|
|
50
|
+
@override
|
|
45
51
|
def command(self, path):
|
|
46
52
|
return "stat -c %C {0} || exit 0".format(path)
|
|
47
53
|
|
|
54
|
+
@override
|
|
48
55
|
def process(self, output):
|
|
49
56
|
context = {}
|
|
50
57
|
components = output[0].split(":")
|
|
@@ -65,12 +72,15 @@ class FileContextMapping(FactBase):
|
|
|
65
72
|
|
|
66
73
|
default = dict
|
|
67
74
|
|
|
75
|
+
@override
|
|
68
76
|
def requires_command(self, target) -> str:
|
|
69
77
|
return "semanage"
|
|
70
78
|
|
|
79
|
+
@override
|
|
71
80
|
def command(self, target):
|
|
72
81
|
return "set -o pipefail && semanage fcontext -n -l | (grep '^{0}' || true)".format(target)
|
|
73
82
|
|
|
83
|
+
@override
|
|
74
84
|
def process(self, output):
|
|
75
85
|
# example output: /etc all files system_u:object_r:etc_t:s0 # noqa: SC100
|
|
76
86
|
# but lines at end that won't match: /etc/systemd/system = /usr/lib/systemd/system
|
|
@@ -97,12 +107,15 @@ class SEPorts(FactBase):
|
|
|
97
107
|
# example output: amqp_port_t tcp 15672, 5671-5672 # noqa: SC100
|
|
98
108
|
_regex = re.compile(r"^([\w_]+)\s+(\w+)\s+([\w\-,\s]+)$")
|
|
99
109
|
|
|
110
|
+
@override
|
|
100
111
|
def requires_command(self) -> str:
|
|
101
112
|
return "semanage"
|
|
102
113
|
|
|
114
|
+
@override
|
|
103
115
|
def command(self):
|
|
104
116
|
return "semanage port -ln"
|
|
105
117
|
|
|
118
|
+
@override
|
|
106
119
|
def process(self, output):
|
|
107
120
|
labels: dict[str, dict] = defaultdict(dict)
|
|
108
121
|
for line in output:
|
|
@@ -132,12 +145,15 @@ class SEPort(FactBase):
|
|
|
132
145
|
|
|
133
146
|
default = str
|
|
134
147
|
|
|
148
|
+
@override
|
|
135
149
|
def requires_command(self, protocol, port) -> str:
|
|
136
150
|
return "sepolicy"
|
|
137
151
|
|
|
152
|
+
@override
|
|
138
153
|
def command(self, protocol, port):
|
|
139
154
|
return "(sepolicy network -p {0} 2>/dev/null || true) | grep {1}".format(port, protocol)
|
|
140
155
|
|
|
156
|
+
@override
|
|
141
157
|
def process(self, output):
|
|
142
158
|
# if type set, first line is specific and second is generic type for port range
|
|
143
159
|
# each rows in the format "22: tcp ssh_port_t 22"
|