pyinfra 2.9.1__py2.py3-none-any.whl → 3.0__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/__init__.py +3 -0
- pyinfra/api/arguments.py +265 -253
- pyinfra/api/arguments_typed.py +80 -0
- pyinfra/api/command.py +68 -53
- pyinfra/api/config.py +139 -32
- pyinfra/api/connect.py +1 -1
- pyinfra/api/connectors.py +7 -26
- pyinfra/api/deploy.py +21 -52
- pyinfra/api/exceptions.py +33 -8
- pyinfra/api/facts.py +102 -137
- pyinfra/api/host.py +150 -82
- pyinfra/api/inventory.py +21 -25
- pyinfra/api/operation.py +240 -198
- pyinfra/api/operations.py +102 -148
- pyinfra/api/state.py +137 -79
- pyinfra/api/util.py +79 -86
- pyinfra/connectors/base.py +147 -0
- pyinfra/connectors/chroot.py +160 -169
- pyinfra/connectors/docker.py +220 -237
- pyinfra/connectors/dockerssh.py +231 -253
- pyinfra/connectors/local.py +196 -208
- pyinfra/connectors/ssh.py +530 -613
- pyinfra/connectors/ssh_util.py +114 -0
- pyinfra/connectors/sshuserclient/client.py +5 -3
- pyinfra/connectors/terraform.py +86 -65
- pyinfra/connectors/util.py +211 -137
- pyinfra/connectors/vagrant.py +60 -53
- pyinfra/context.py +4 -2
- pyinfra/facts/apk.py +2 -0
- pyinfra/facts/apt.py +2 -0
- pyinfra/facts/brew.py +2 -0
- pyinfra/facts/bsdinit.py +2 -0
- pyinfra/facts/cargo.py +2 -0
- pyinfra/facts/choco.py +2 -0
- pyinfra/facts/deb.py +7 -2
- pyinfra/facts/dnf.py +2 -0
- pyinfra/facts/docker.py +19 -0
- pyinfra/facts/files.py +47 -32
- pyinfra/facts/gem.py +2 -0
- pyinfra/facts/git.py +3 -1
- pyinfra/facts/gpg.py +3 -1
- pyinfra/facts/hardware.py +34 -24
- pyinfra/facts/iptables.py +5 -3
- pyinfra/facts/launchd.py +2 -0
- pyinfra/facts/lxd.py +2 -0
- pyinfra/facts/mysql.py +13 -6
- pyinfra/facts/npm.py +1 -0
- pyinfra/facts/openrc.py +2 -0
- pyinfra/facts/pacman.py +6 -2
- pyinfra/facts/pip.py +2 -0
- pyinfra/facts/pkg.py +2 -0
- pyinfra/facts/pkgin.py +2 -0
- pyinfra/facts/postgres.py +168 -0
- pyinfra/facts/postgresql.py +6 -160
- pyinfra/facts/rpm.py +12 -9
- pyinfra/facts/runit.py +68 -0
- pyinfra/facts/selinux.py +3 -1
- pyinfra/facts/server.py +80 -36
- pyinfra/facts/snap.py +2 -0
- pyinfra/facts/systemd.py +31 -12
- pyinfra/facts/sysvinit.py +10 -10
- pyinfra/facts/upstart.py +2 -0
- pyinfra/facts/util/packaging.py +7 -4
- pyinfra/facts/vzctl.py +2 -0
- pyinfra/facts/xbps.py +2 -0
- pyinfra/facts/yum.py +2 -0
- pyinfra/facts/zypper.py +2 -0
- pyinfra/local.py +4 -5
- pyinfra/operations/apk.py +6 -4
- pyinfra/operations/apt.py +46 -65
- pyinfra/operations/brew.py +17 -22
- pyinfra/operations/bsdinit.py +9 -7
- pyinfra/operations/cargo.py +4 -2
- pyinfra/operations/choco.py +4 -2
- pyinfra/operations/dnf.py +19 -23
- pyinfra/operations/docker.py +339 -0
- pyinfra/operations/files.py +188 -386
- pyinfra/operations/gem.py +4 -2
- pyinfra/operations/git.py +24 -53
- pyinfra/operations/iptables.py +29 -35
- pyinfra/operations/launchd.py +6 -7
- pyinfra/operations/lxd.py +8 -13
- pyinfra/operations/mysql.py +62 -81
- pyinfra/operations/npm.py +9 -2
- pyinfra/operations/openrc.py +6 -4
- pyinfra/operations/pacman.py +7 -8
- pyinfra/operations/pip.py +25 -24
- pyinfra/operations/pkg.py +4 -2
- pyinfra/operations/pkgin.py +6 -4
- pyinfra/operations/postgres.py +349 -0
- pyinfra/operations/postgresql.py +18 -379
- pyinfra/operations/puppet.py +3 -1
- pyinfra/operations/python.py +8 -19
- pyinfra/operations/runit.py +182 -0
- pyinfra/operations/selinux.py +47 -44
- pyinfra/operations/server.py +111 -127
- pyinfra/operations/snap.py +4 -4
- pyinfra/operations/ssh.py +20 -33
- pyinfra/operations/systemd.py +19 -15
- pyinfra/operations/sysvinit.py +9 -16
- pyinfra/operations/upstart.py +9 -7
- pyinfra/operations/util/__init__.py +12 -0
- pyinfra/operations/util/docker.py +177 -0
- pyinfra/operations/util/files.py +24 -16
- pyinfra/operations/util/packaging.py +55 -57
- pyinfra/operations/util/service.py +39 -51
- pyinfra/operations/vzctl.py +12 -10
- pyinfra/operations/xbps.py +6 -4
- pyinfra/operations/yum.py +18 -22
- pyinfra/operations/zypper.py +12 -13
- pyinfra/version.py +5 -2
- {pyinfra-2.9.1.dist-info → pyinfra-3.0.dist-info}/METADATA +40 -41
- pyinfra-3.0.dist-info/RECORD +167 -0
- {pyinfra-2.9.1.dist-info → pyinfra-3.0.dist-info}/WHEEL +1 -1
- pyinfra-3.0.dist-info/entry_points.txt +11 -0
- pyinfra_cli/__main__.py +4 -3
- pyinfra_cli/commands.py +7 -2
- pyinfra_cli/exceptions.py +78 -42
- pyinfra_cli/inventory.py +40 -6
- pyinfra_cli/log.py +17 -3
- pyinfra_cli/main.py +133 -90
- pyinfra_cli/prints.py +95 -127
- pyinfra_cli/util.py +62 -29
- tests/test_api/test_api.py +2 -0
- tests/test_api/test_api_arguments.py +13 -13
- tests/test_api/test_api_deploys.py +28 -29
- tests/test_api/test_api_facts.py +60 -98
- tests/test_api/test_api_operations.py +101 -201
- tests/test_cli/test_cli.py +18 -49
- tests/test_cli/test_cli_deploy.py +11 -37
- tests/test_cli/test_cli_exceptions.py +50 -19
- tests/test_cli/util.py +1 -1
- tests/test_connectors/test_chroot.py +6 -6
- tests/test_connectors/test_docker.py +4 -4
- tests/test_connectors/test_dockerssh.py +38 -50
- tests/test_connectors/test_local.py +11 -12
- tests/test_connectors/test_ssh.py +105 -93
- tests/test_connectors/test_terraform.py +9 -15
- tests/test_connectors/test_util.py +24 -46
- tests/test_connectors/test_vagrant.py +7 -7
- pyinfra/api/operation.pyi +0 -117
- pyinfra/connectors/ansible.py +0 -171
- pyinfra/connectors/mech.py +0 -186
- pyinfra/connectors/pyinfrawinrmsession/__init__.py +0 -28
- pyinfra/connectors/winrm.py +0 -320
- pyinfra/facts/windows.py +0 -366
- pyinfra/facts/windows_files.py +0 -90
- pyinfra/operations/windows.py +0 -59
- pyinfra/operations/windows_files.py +0 -551
- pyinfra-2.9.1.dist-info/RECORD +0 -170
- pyinfra-2.9.1.dist-info/entry_points.txt +0 -14
- tests/test_connectors/test_ansible.py +0 -64
- tests/test_connectors/test_mech.py +0 -126
- tests/test_connectors/test_winrm.py +0 -76
- {pyinfra-2.9.1.dist-info → pyinfra-3.0.dist-info}/LICENSE.md +0 -0
- {pyinfra-2.9.1.dist-info → pyinfra-3.0.dist-info}/top_level.txt +0 -0
pyinfra/facts/postgresql.py
CHANGED
|
@@ -1,165 +1,11 @@
|
|
|
1
|
-
from
|
|
2
|
-
from pyinfra.api.util import try_int
|
|
1
|
+
from __future__ import annotations
|
|
3
2
|
|
|
4
|
-
from .
|
|
3
|
+
from .postgres import PostgresDatabases, PostgresRoles
|
|
5
4
|
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
user=None,
|
|
10
|
-
password=None,
|
|
11
|
-
host=None,
|
|
12
|
-
port=None,
|
|
13
|
-
executable="psql",
|
|
14
|
-
):
|
|
15
|
-
target_bits = []
|
|
6
|
+
class PostgresqlRoles(PostgresRoles):
|
|
7
|
+
deprecated = True
|
|
16
8
|
|
|
17
|
-
if password:
|
|
18
|
-
target_bits.append(MaskString('PGPASSWORD="{0}"'.format(password)))
|
|
19
9
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if database:
|
|
23
|
-
target_bits.append("-d {0}".format(database))
|
|
24
|
-
|
|
25
|
-
if user:
|
|
26
|
-
target_bits.append("-U {0}".format(user))
|
|
27
|
-
|
|
28
|
-
if host:
|
|
29
|
-
target_bits.append("-h {0}".format(host))
|
|
30
|
-
|
|
31
|
-
if port:
|
|
32
|
-
target_bits.append("-p {0}".format(port))
|
|
33
|
-
|
|
34
|
-
return StringCommand(*target_bits)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def make_execute_psql_command(command, **psql_kwargs):
|
|
38
|
-
return StringCommand(
|
|
39
|
-
make_psql_command(**psql_kwargs),
|
|
40
|
-
"-Ac",
|
|
41
|
-
QuoteString(command), # quote this whole item as a single shell argument
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class PostgresqlFactBase(FactBase):
|
|
46
|
-
abstract = True
|
|
47
|
-
|
|
48
|
-
requires_command = "psql"
|
|
49
|
-
|
|
50
|
-
def command(
|
|
51
|
-
self,
|
|
52
|
-
psql_user=None,
|
|
53
|
-
psql_password=None,
|
|
54
|
-
psql_host=None,
|
|
55
|
-
psql_port=None,
|
|
56
|
-
):
|
|
57
|
-
return make_execute_psql_command(
|
|
58
|
-
self.psql_command,
|
|
59
|
-
user=psql_user,
|
|
60
|
-
password=psql_password,
|
|
61
|
-
host=psql_host,
|
|
62
|
-
port=psql_port,
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
class PostgresqlRoles(PostgresqlFactBase):
|
|
67
|
-
"""
|
|
68
|
-
Returns a dict of PostgreSQL roles and data:
|
|
69
|
-
|
|
70
|
-
.. code:: python
|
|
71
|
-
|
|
72
|
-
{
|
|
73
|
-
"pyinfra": {
|
|
74
|
-
"super": true,
|
|
75
|
-
"createrole": false,
|
|
76
|
-
"createdb": false,
|
|
77
|
-
...
|
|
78
|
-
},
|
|
79
|
-
}
|
|
80
|
-
"""
|
|
81
|
-
|
|
82
|
-
default = dict
|
|
83
|
-
psql_command = "SELECT * FROM pg_catalog.pg_roles"
|
|
84
|
-
|
|
85
|
-
def process(self, output):
|
|
86
|
-
# Remove the last line of the output (row count)
|
|
87
|
-
output = output[:-1]
|
|
88
|
-
rows = parse_columns_and_rows(
|
|
89
|
-
output,
|
|
90
|
-
"|",
|
|
91
|
-
# Remove the "rol" prefix on column names
|
|
92
|
-
remove_column_prefix="rol",
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
users = {}
|
|
96
|
-
|
|
97
|
-
for details in rows:
|
|
98
|
-
for key, value in list(details.items()):
|
|
99
|
-
if key in ("oid", "connlimit"):
|
|
100
|
-
details[key] = try_int(value)
|
|
101
|
-
|
|
102
|
-
if key in (
|
|
103
|
-
"super",
|
|
104
|
-
"inherit",
|
|
105
|
-
"createrole",
|
|
106
|
-
"createdb",
|
|
107
|
-
"canlogin",
|
|
108
|
-
"replication",
|
|
109
|
-
"bypassrls",
|
|
110
|
-
):
|
|
111
|
-
details[key] = value == "t"
|
|
112
|
-
|
|
113
|
-
users[details.pop("name")] = details
|
|
114
|
-
|
|
115
|
-
return users
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
class PostgresqlDatabases(PostgresqlFactBase):
|
|
119
|
-
"""
|
|
120
|
-
Returns a dict of PostgreSQL databases and metadata:
|
|
121
|
-
|
|
122
|
-
.. code:: python
|
|
123
|
-
|
|
124
|
-
{
|
|
125
|
-
"pyinfra_stuff": {
|
|
126
|
-
"encoding": "UTF8",
|
|
127
|
-
"collate": "en_US.UTF-8",
|
|
128
|
-
"ctype": "en_US.UTF-8",
|
|
129
|
-
...
|
|
130
|
-
},
|
|
131
|
-
}
|
|
132
|
-
"""
|
|
133
|
-
|
|
134
|
-
default = dict
|
|
135
|
-
psql_command = "SELECT pg_catalog.pg_encoding_to_char(encoding), * FROM pg_catalog.pg_database"
|
|
136
|
-
|
|
137
|
-
def process(self, output):
|
|
138
|
-
# Remove the last line of the output (row count)
|
|
139
|
-
output = output[:-1]
|
|
140
|
-
rows = parse_columns_and_rows(
|
|
141
|
-
output,
|
|
142
|
-
"|",
|
|
143
|
-
# Remove the "dat" prefix on column names
|
|
144
|
-
remove_column_prefix="dat",
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
databases = {}
|
|
148
|
-
|
|
149
|
-
for details in rows:
|
|
150
|
-
details["encoding"] = details.pop("pg_encoding_to_char")
|
|
151
|
-
|
|
152
|
-
for key, value in list(details.items()):
|
|
153
|
-
if key.endswith("id") or key in (
|
|
154
|
-
"dba",
|
|
155
|
-
"tablespace",
|
|
156
|
-
"connlimit",
|
|
157
|
-
):
|
|
158
|
-
details[key] = try_int(value)
|
|
159
|
-
|
|
160
|
-
if key in ("istemplate", "allowconn"):
|
|
161
|
-
details[key] = value == "t"
|
|
162
|
-
|
|
163
|
-
databases[details.pop("name")] = details
|
|
164
|
-
|
|
165
|
-
return databases
|
|
10
|
+
class PostgresqlDatabases(PostgresDatabases):
|
|
11
|
+
deprecated = True
|
pyinfra/facts/rpm.py
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import re
|
|
4
|
+
import shlex
|
|
2
5
|
|
|
3
6
|
from pyinfra.api import FactBase
|
|
4
7
|
|
|
@@ -19,7 +22,7 @@ class RpmPackages(FactBase):
|
|
|
19
22
|
}
|
|
20
23
|
"""
|
|
21
24
|
|
|
22
|
-
command =
|
|
25
|
+
command = "rpm --queryformat {0} -qa".format(shlex.quote(rpm_query_format))
|
|
23
26
|
requires_command = "rpm"
|
|
24
27
|
|
|
25
28
|
default = dict
|
|
@@ -42,12 +45,12 @@ class RpmPackage(FactBase):
|
|
|
42
45
|
|
|
43
46
|
requires_command = "rpm"
|
|
44
47
|
|
|
45
|
-
def command(self,
|
|
48
|
+
def command(self, package):
|
|
46
49
|
return (
|
|
47
|
-
|
|
50
|
+
"rpm --queryformat {0} -q {1} || "
|
|
48
51
|
"! test -e {1} || "
|
|
49
|
-
|
|
50
|
-
).format(rpm_query_format,
|
|
52
|
+
"rpm --queryformat {0} -qp {1} 2> /dev/null"
|
|
53
|
+
).format(shlex.quote(rpm_query_format), shlex.quote(package))
|
|
51
54
|
|
|
52
55
|
def process(self, output):
|
|
53
56
|
for line in output:
|
|
@@ -69,11 +72,11 @@ class RpmPackageProvides(FactBase):
|
|
|
69
72
|
requires_command = "repoquery"
|
|
70
73
|
|
|
71
74
|
@staticmethod
|
|
72
|
-
def command(
|
|
75
|
+
def command(package):
|
|
73
76
|
# Accept failure here (|| true) for invalid/unknown packages
|
|
74
|
-
return
|
|
75
|
-
rpm_query_format,
|
|
76
|
-
|
|
77
|
+
return "repoquery --queryformat {0} --whatprovides {1} || true".format(
|
|
78
|
+
shlex.quote(rpm_query_format),
|
|
79
|
+
shlex.quote(package),
|
|
77
80
|
)
|
|
78
81
|
|
|
79
82
|
@staticmethod
|
pyinfra/facts/runit.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from pyinfra.api import FactBase
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class RunitStatus(FactBase):
|
|
5
|
+
"""
|
|
6
|
+
Returns a dict of name -> status for runit services.
|
|
7
|
+
|
|
8
|
+
+ service: optionally check only for a single service
|
|
9
|
+
+ svdir: alternative ``SVDIR``
|
|
10
|
+
|
|
11
|
+
.. code:: python
|
|
12
|
+
|
|
13
|
+
{
|
|
14
|
+
'agetty-tty1': True, # service is running
|
|
15
|
+
'dhcpcd': False, # service is down
|
|
16
|
+
'wpa_supplicant': None, # service is managed, but not running or down,
|
|
17
|
+
# possibly in a fail state
|
|
18
|
+
}
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
requires_command = "sv"
|
|
22
|
+
default = dict
|
|
23
|
+
|
|
24
|
+
def command(self, service=None, svdir="/var/service"):
|
|
25
|
+
if service is None:
|
|
26
|
+
return (
|
|
27
|
+
'export SVDIR="{0}" && '
|
|
28
|
+
'cd "$SVDIR" && find * -maxdepth 0 -exec sv status {{}} + 2>/dev/null'
|
|
29
|
+
).format(svdir)
|
|
30
|
+
else:
|
|
31
|
+
return 'SVDIR="{0}" sv status "{1}"'.format(svdir, service)
|
|
32
|
+
|
|
33
|
+
def process(self, output):
|
|
34
|
+
services = {}
|
|
35
|
+
for line in output:
|
|
36
|
+
statusstr, service, _ = line.split(sep=": ", maxsplit=2)
|
|
37
|
+
status = None
|
|
38
|
+
|
|
39
|
+
if statusstr == "run":
|
|
40
|
+
status = True
|
|
41
|
+
elif statusstr == "down":
|
|
42
|
+
status = False
|
|
43
|
+
# another observable state is "fail"
|
|
44
|
+
# report as ``None`` for now
|
|
45
|
+
|
|
46
|
+
services[service] = status
|
|
47
|
+
|
|
48
|
+
return services
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class RunitManaged(FactBase):
|
|
52
|
+
"""
|
|
53
|
+
Returns a set of all services managed by runit
|
|
54
|
+
|
|
55
|
+
+ service: optionally check only for a single service
|
|
56
|
+
+ svdir: alternative ``SVDIR``
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
default = set
|
|
60
|
+
|
|
61
|
+
def command(self, service=None, svdir="/var/service"):
|
|
62
|
+
if service is None:
|
|
63
|
+
return 'cd "{0}" && find -mindepth 1 -maxdepth 1 -type l -printf "%f\n"'.format(svdir)
|
|
64
|
+
else:
|
|
65
|
+
return 'cd "{0}" && test -h "{1}" && echo "{1}" || true'.format(svdir, service)
|
|
66
|
+
|
|
67
|
+
def process(self, output):
|
|
68
|
+
return set(output)
|
pyinfra/facts/selinux.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import re
|
|
2
4
|
from collections import defaultdict
|
|
3
5
|
|
|
@@ -94,7 +96,7 @@ class SEPorts(FactBase):
|
|
|
94
96
|
return "semanage port -ln"
|
|
95
97
|
|
|
96
98
|
def process(self, output):
|
|
97
|
-
labels = defaultdict(dict)
|
|
99
|
+
labels: dict[str, dict] = defaultdict(dict)
|
|
98
100
|
for line in output:
|
|
99
101
|
m = SEPorts._regex.match(line)
|
|
100
102
|
if m is None: # something went wrong
|
pyinfra/facts/server.py
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import os
|
|
2
4
|
import re
|
|
3
5
|
import shutil
|
|
4
6
|
from datetime import datetime
|
|
5
7
|
from tempfile import mkdtemp
|
|
8
|
+
from typing import Dict, List, Optional, Union
|
|
6
9
|
|
|
7
10
|
from dateutil.parser import parse as parse_date
|
|
8
11
|
from distro import distro
|
|
12
|
+
from typing_extensions import NotRequired, TypedDict
|
|
9
13
|
|
|
10
14
|
from pyinfra.api import FactBase, ShortFactBase
|
|
11
15
|
from pyinfra.api.util import try_int
|
|
@@ -21,12 +25,14 @@ class User(FactBase):
|
|
|
21
25
|
command = "echo $USER"
|
|
22
26
|
|
|
23
27
|
|
|
24
|
-
class Home(FactBase):
|
|
28
|
+
class Home(FactBase[Optional[str]]):
|
|
25
29
|
"""
|
|
26
|
-
Returns the home directory of the current user.
|
|
30
|
+
Returns the home directory of the given user, or the current user if no user is given.
|
|
27
31
|
"""
|
|
28
32
|
|
|
29
|
-
|
|
33
|
+
@staticmethod
|
|
34
|
+
def command(user=""):
|
|
35
|
+
return f"echo ~{user}"
|
|
30
36
|
|
|
31
37
|
|
|
32
38
|
class Path(FactBase):
|
|
@@ -37,6 +43,14 @@ class Path(FactBase):
|
|
|
37
43
|
command = "echo $PATH"
|
|
38
44
|
|
|
39
45
|
|
|
46
|
+
class TmpDir(FactBase):
|
|
47
|
+
"""
|
|
48
|
+
Returns the temporary directory of the current server, if configured.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
command = "echo $TMPDIR"
|
|
52
|
+
|
|
53
|
+
|
|
40
54
|
class Hostname(FactBase):
|
|
41
55
|
"""
|
|
42
56
|
Returns the current hostname of the server.
|
|
@@ -62,7 +76,7 @@ class KernelVersion(FactBase):
|
|
|
62
76
|
|
|
63
77
|
|
|
64
78
|
# Deprecated/renamed -> Kernel
|
|
65
|
-
class Os(FactBase):
|
|
79
|
+
class Os(FactBase[str]):
|
|
66
80
|
"""
|
|
67
81
|
Returns the OS name according to ``uname``.
|
|
68
82
|
|
|
@@ -74,7 +88,7 @@ class Os(FactBase):
|
|
|
74
88
|
|
|
75
89
|
|
|
76
90
|
# Deprecated/renamed -> KernelVersion
|
|
77
|
-
class OsVersion(FactBase):
|
|
91
|
+
class OsVersion(FactBase[str]):
|
|
78
92
|
"""
|
|
79
93
|
Returns the OS version according to ``uname``.
|
|
80
94
|
|
|
@@ -85,7 +99,7 @@ class OsVersion(FactBase):
|
|
|
85
99
|
command = "uname -r"
|
|
86
100
|
|
|
87
101
|
|
|
88
|
-
class Arch(FactBase):
|
|
102
|
+
class Arch(FactBase[str]):
|
|
89
103
|
"""
|
|
90
104
|
Returns the system architecture according to ``uname``.
|
|
91
105
|
"""
|
|
@@ -95,7 +109,7 @@ class Arch(FactBase):
|
|
|
95
109
|
command = "uname -m"
|
|
96
110
|
|
|
97
111
|
|
|
98
|
-
class Command(FactBase):
|
|
112
|
+
class Command(FactBase[str]):
|
|
99
113
|
"""
|
|
100
114
|
Returns the raw output lines of a given command.
|
|
101
115
|
"""
|
|
@@ -105,7 +119,7 @@ class Command(FactBase):
|
|
|
105
119
|
return command
|
|
106
120
|
|
|
107
121
|
|
|
108
|
-
class Which(FactBase):
|
|
122
|
+
class Which(FactBase[Optional[str]]):
|
|
109
123
|
"""
|
|
110
124
|
Returns the path of a given command, if available.
|
|
111
125
|
"""
|
|
@@ -115,7 +129,7 @@ class Which(FactBase):
|
|
|
115
129
|
return "which {0} || true".format(command)
|
|
116
130
|
|
|
117
131
|
|
|
118
|
-
class Date(FactBase):
|
|
132
|
+
class Date(FactBase[datetime]):
|
|
119
133
|
"""
|
|
120
134
|
Returns the current datetime on the server.
|
|
121
135
|
"""
|
|
@@ -124,11 +138,11 @@ class Date(FactBase):
|
|
|
124
138
|
default = datetime.now
|
|
125
139
|
|
|
126
140
|
@staticmethod
|
|
127
|
-
def process(output):
|
|
141
|
+
def process(output) -> datetime:
|
|
128
142
|
return datetime.strptime(output[0], ISO_DATE_FORMAT)
|
|
129
143
|
|
|
130
144
|
|
|
131
|
-
class MacosVersion(FactBase):
|
|
145
|
+
class MacosVersion(FactBase[str]):
|
|
132
146
|
"""
|
|
133
147
|
Returns the installed MacOS version.
|
|
134
148
|
"""
|
|
@@ -137,7 +151,13 @@ class MacosVersion(FactBase):
|
|
|
137
151
|
requires_command = "sw_vers"
|
|
138
152
|
|
|
139
153
|
|
|
140
|
-
class
|
|
154
|
+
class MountsDict(TypedDict):
|
|
155
|
+
device: str
|
|
156
|
+
type: str
|
|
157
|
+
options: list[str]
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class Mounts(FactBase[Dict[str, MountsDict]]):
|
|
141
161
|
"""
|
|
142
162
|
Returns a dictionary of mounted filesystems and information.
|
|
143
163
|
|
|
@@ -159,8 +179,8 @@ class Mounts(FactBase):
|
|
|
159
179
|
default = dict
|
|
160
180
|
|
|
161
181
|
@staticmethod
|
|
162
|
-
def process(output):
|
|
163
|
-
devices = {}
|
|
182
|
+
def process(output) -> dict[str, MountsDict]:
|
|
183
|
+
devices: dict[str, MountsDict] = {}
|
|
164
184
|
|
|
165
185
|
for line in output:
|
|
166
186
|
is_map = False
|
|
@@ -285,9 +305,14 @@ class Sysctl(FactBase):
|
|
|
285
305
|
}
|
|
286
306
|
"""
|
|
287
307
|
|
|
288
|
-
command = "sysctl -a"
|
|
289
308
|
default = dict
|
|
290
309
|
|
|
310
|
+
@staticmethod
|
|
311
|
+
def command(keys=None):
|
|
312
|
+
if keys is None:
|
|
313
|
+
return "sysctl -a"
|
|
314
|
+
return f"sysctl {' '.join(keys)}"
|
|
315
|
+
|
|
291
316
|
@staticmethod
|
|
292
317
|
def process(output):
|
|
293
318
|
sysctls = {}
|
|
@@ -317,7 +342,7 @@ class Sysctl(FactBase):
|
|
|
317
342
|
return sysctls
|
|
318
343
|
|
|
319
344
|
|
|
320
|
-
class Groups(FactBase):
|
|
345
|
+
class Groups(FactBase[List[str]]):
|
|
321
346
|
"""
|
|
322
347
|
Returns a list of groups on the system.
|
|
323
348
|
"""
|
|
@@ -325,9 +350,8 @@ class Groups(FactBase):
|
|
|
325
350
|
command = "cat /etc/group"
|
|
326
351
|
default = list
|
|
327
352
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
groups = []
|
|
353
|
+
def process(self, output) -> list[str]:
|
|
354
|
+
groups: list[str] = []
|
|
331
355
|
|
|
332
356
|
for line in output:
|
|
333
357
|
if ":" in line:
|
|
@@ -336,7 +360,17 @@ class Groups(FactBase):
|
|
|
336
360
|
return groups
|
|
337
361
|
|
|
338
362
|
|
|
339
|
-
class
|
|
363
|
+
class CrontabDict(TypedDict):
|
|
364
|
+
minute: NotRequired[Union[int, str]]
|
|
365
|
+
hour: NotRequired[Union[int, str]]
|
|
366
|
+
month: NotRequired[Union[int, str]]
|
|
367
|
+
day_of_month: NotRequired[Union[int, str]]
|
|
368
|
+
day_of_week: NotRequired[Union[int, str]]
|
|
369
|
+
comments: Optional[list[str]]
|
|
370
|
+
special_time: NotRequired[str]
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
class Crontab(FactBase[Dict[str, CrontabDict]]):
|
|
340
374
|
"""
|
|
341
375
|
Returns a dictionary of cron command -> execution time.
|
|
342
376
|
|
|
@@ -366,9 +400,8 @@ class Crontab(FactBase):
|
|
|
366
400
|
return "crontab -l -u {0} || true".format(user)
|
|
367
401
|
return "crontab -l || true"
|
|
368
402
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
crons = {}
|
|
403
|
+
def process(self, output):
|
|
404
|
+
crons: dict[str, CrontabDict] = {}
|
|
372
405
|
current_comments = []
|
|
373
406
|
|
|
374
407
|
for line in output:
|
|
@@ -478,7 +511,14 @@ class Users(FactBase):
|
|
|
478
511
|
return users
|
|
479
512
|
|
|
480
513
|
|
|
481
|
-
class
|
|
514
|
+
class LinuxDistributionDict(TypedDict):
|
|
515
|
+
name: Optional[str]
|
|
516
|
+
major: Optional[int]
|
|
517
|
+
minor: Optional[int]
|
|
518
|
+
release_meta: Dict
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
class LinuxDistribution(FactBase[LinuxDistributionDict]):
|
|
482
522
|
"""
|
|
483
523
|
Returns a dict of the Linux distribution version. Ubuntu, Debian, CentOS,
|
|
484
524
|
Fedora & Gentoo currently. Also contains any key/value items located in
|
|
@@ -516,7 +556,7 @@ class LinuxDistribution(FactBase):
|
|
|
516
556
|
}
|
|
517
557
|
|
|
518
558
|
@staticmethod
|
|
519
|
-
def default():
|
|
559
|
+
def default() -> LinuxDistributionDict:
|
|
520
560
|
return {
|
|
521
561
|
"name": None,
|
|
522
562
|
"major": None,
|
|
@@ -524,7 +564,7 @@ class LinuxDistribution(FactBase):
|
|
|
524
564
|
"release_meta": {},
|
|
525
565
|
}
|
|
526
566
|
|
|
527
|
-
def process(self, output):
|
|
567
|
+
def process(self, output) -> LinuxDistributionDict:
|
|
528
568
|
parts = {}
|
|
529
569
|
for part in "\n".join(output).strip().split("---"):
|
|
530
570
|
if not part.strip():
|
|
@@ -578,7 +618,7 @@ class LinuxDistribution(FactBase):
|
|
|
578
618
|
return release_info
|
|
579
619
|
|
|
580
620
|
|
|
581
|
-
class LinuxName(ShortFactBase):
|
|
621
|
+
class LinuxName(ShortFactBase[str]):
|
|
582
622
|
"""
|
|
583
623
|
Returns the name of the Linux distribution. Shortcut for
|
|
584
624
|
``host.get_fact(LinuxDistribution)['name']``.
|
|
@@ -591,7 +631,11 @@ class LinuxName(ShortFactBase):
|
|
|
591
631
|
return data["name"]
|
|
592
632
|
|
|
593
633
|
|
|
594
|
-
class
|
|
634
|
+
class SelinuxDict(TypedDict):
|
|
635
|
+
mode: Optional[str]
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
class Selinux(FactBase[SelinuxDict]):
|
|
595
639
|
"""
|
|
596
640
|
Discovers the SELinux related facts on the target host.
|
|
597
641
|
|
|
@@ -606,12 +650,12 @@ class Selinux(FactBase):
|
|
|
606
650
|
requires_command = "sestatus"
|
|
607
651
|
|
|
608
652
|
@staticmethod
|
|
609
|
-
def default():
|
|
653
|
+
def default() -> SelinuxDict:
|
|
610
654
|
return {
|
|
611
655
|
"mode": None,
|
|
612
656
|
}
|
|
613
657
|
|
|
614
|
-
def process(self, output):
|
|
658
|
+
def process(self, output) -> SelinuxDict:
|
|
615
659
|
selinux_info = self.default()
|
|
616
660
|
|
|
617
661
|
match = re.match(r"^SELinux status:\s+(\S+)", "\n".join(output))
|
|
@@ -624,7 +668,7 @@ class Selinux(FactBase):
|
|
|
624
668
|
return selinux_info
|
|
625
669
|
|
|
626
670
|
|
|
627
|
-
class LinuxGui(FactBase):
|
|
671
|
+
class LinuxGui(FactBase[List[str]]):
|
|
628
672
|
"""
|
|
629
673
|
Returns a list of available Linux GUIs.
|
|
630
674
|
"""
|
|
@@ -640,7 +684,7 @@ class LinuxGui(FactBase):
|
|
|
640
684
|
"/usr/bin/xfce4-session": "XFCE 4",
|
|
641
685
|
}
|
|
642
686
|
|
|
643
|
-
def process(self, output):
|
|
687
|
+
def process(self, output) -> list[str]:
|
|
644
688
|
gui_names = []
|
|
645
689
|
|
|
646
690
|
for line in output:
|
|
@@ -651,7 +695,7 @@ class LinuxGui(FactBase):
|
|
|
651
695
|
return gui_names
|
|
652
696
|
|
|
653
697
|
|
|
654
|
-
class HasGui(ShortFactBase):
|
|
698
|
+
class HasGui(ShortFactBase[bool]):
|
|
655
699
|
"""
|
|
656
700
|
Returns a boolean indicating the remote side has GUI capabilities. Linux only.
|
|
657
701
|
"""
|
|
@@ -659,11 +703,11 @@ class HasGui(ShortFactBase):
|
|
|
659
703
|
fact = LinuxGui
|
|
660
704
|
|
|
661
705
|
@staticmethod
|
|
662
|
-
def process_data(data):
|
|
706
|
+
def process_data(data) -> bool:
|
|
663
707
|
return len(data) > 0
|
|
664
708
|
|
|
665
709
|
|
|
666
|
-
class Locales(FactBase):
|
|
710
|
+
class Locales(FactBase[List[str]]):
|
|
667
711
|
"""
|
|
668
712
|
Returns installed locales on the target host.
|
|
669
713
|
|
|
@@ -676,7 +720,7 @@ class Locales(FactBase):
|
|
|
676
720
|
requires_command = "locale"
|
|
677
721
|
default = list
|
|
678
722
|
|
|
679
|
-
def process(self, output):
|
|
723
|
+
def process(self, output) -> list[str]:
|
|
680
724
|
# replace utf8 with UTF-8 to match names in /etc/locale.gen
|
|
681
725
|
# return a list of enabled locales
|
|
682
726
|
return [line.replace("utf8", "UTF-8") for line in output]
|