pyinfra 3.0.dev0__py2.py3-none-any.whl → 3.0.2__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 +115 -97
- pyinfra/api/arguments_typed.py +80 -0
- pyinfra/api/command.py +5 -3
- pyinfra/api/config.py +139 -39
- pyinfra/api/connectors.py +5 -2
- pyinfra/api/deploy.py +19 -19
- pyinfra/api/exceptions.py +35 -4
- pyinfra/api/facts.py +62 -86
- pyinfra/api/host.py +102 -15
- pyinfra/api/inventory.py +4 -0
- pyinfra/api/operation.py +188 -120
- pyinfra/api/operations.py +66 -113
- pyinfra/api/state.py +53 -34
- pyinfra/api/util.py +64 -33
- pyinfra/connectors/base.py +65 -20
- pyinfra/connectors/chroot.py +15 -13
- pyinfra/connectors/docker.py +62 -72
- pyinfra/connectors/dockerssh.py +20 -19
- pyinfra/connectors/local.py +32 -22
- pyinfra/connectors/ssh.py +162 -86
- pyinfra/connectors/sshuserclient/client.py +1 -1
- pyinfra/connectors/terraform.py +57 -39
- pyinfra/connectors/util.py +26 -27
- pyinfra/connectors/vagrant.py +27 -26
- pyinfra/context.py +1 -0
- pyinfra/facts/apk.py +7 -2
- pyinfra/facts/apt.py +15 -7
- pyinfra/facts/brew.py +28 -13
- pyinfra/facts/bsdinit.py +9 -6
- pyinfra/facts/cargo.py +6 -3
- pyinfra/facts/choco.py +8 -4
- pyinfra/facts/deb.py +21 -9
- pyinfra/facts/dnf.py +11 -6
- pyinfra/facts/docker.py +30 -5
- pyinfra/facts/files.py +49 -33
- pyinfra/facts/gem.py +7 -2
- pyinfra/facts/git.py +14 -21
- pyinfra/facts/gpg.py +4 -1
- pyinfra/facts/hardware.py +186 -138
- pyinfra/facts/launchd.py +7 -2
- pyinfra/facts/lxd.py +8 -2
- pyinfra/facts/mysql.py +19 -12
- pyinfra/facts/npm.py +3 -1
- pyinfra/facts/openrc.py +8 -2
- pyinfra/facts/pacman.py +13 -5
- pyinfra/facts/pip.py +2 -0
- pyinfra/facts/pkg.py +5 -1
- pyinfra/facts/pkgin.py +7 -2
- pyinfra/facts/postgres.py +170 -0
- pyinfra/facts/postgresql.py +5 -162
- pyinfra/facts/rpm.py +21 -15
- pyinfra/facts/runit.py +70 -0
- pyinfra/facts/selinux.py +12 -4
- pyinfra/facts/server.py +240 -82
- pyinfra/facts/snap.py +8 -2
- pyinfra/facts/systemd.py +37 -13
- pyinfra/facts/sysvinit.py +7 -4
- pyinfra/facts/upstart.py +7 -2
- pyinfra/facts/util/packaging.py +3 -2
- pyinfra/facts/vzctl.py +8 -4
- pyinfra/facts/xbps.py +7 -2
- pyinfra/facts/yum.py +10 -5
- pyinfra/facts/zypper.py +9 -4
- pyinfra/operations/apk.py +5 -3
- pyinfra/operations/apt.py +28 -25
- pyinfra/operations/brew.py +60 -29
- pyinfra/operations/bsdinit.py +6 -4
- pyinfra/operations/cargo.py +3 -1
- pyinfra/operations/choco.py +3 -1
- pyinfra/operations/dnf.py +16 -20
- pyinfra/operations/docker.py +339 -0
- pyinfra/operations/files.py +187 -168
- pyinfra/operations/gem.py +3 -1
- pyinfra/operations/git.py +23 -25
- pyinfra/operations/iptables.py +33 -25
- pyinfra/operations/launchd.py +5 -6
- pyinfra/operations/lxd.py +7 -4
- pyinfra/operations/mysql.py +59 -55
- pyinfra/operations/npm.py +8 -1
- pyinfra/operations/openrc.py +5 -3
- pyinfra/operations/pacman.py +6 -7
- pyinfra/operations/pip.py +19 -12
- pyinfra/operations/pkg.py +3 -1
- pyinfra/operations/pkgin.py +5 -3
- pyinfra/operations/postgres.py +349 -0
- pyinfra/operations/postgresql.py +18 -335
- pyinfra/operations/puppet.py +3 -1
- pyinfra/operations/python.py +8 -19
- pyinfra/operations/runit.py +182 -0
- pyinfra/operations/selinux.py +47 -29
- pyinfra/operations/server.py +138 -67
- pyinfra/operations/snap.py +3 -1
- pyinfra/operations/ssh.py +18 -16
- pyinfra/operations/systemd.py +18 -12
- pyinfra/operations/sysvinit.py +7 -5
- pyinfra/operations/upstart.py +7 -5
- 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 +54 -38
- pyinfra/operations/util/service.py +39 -47
- pyinfra/operations/vzctl.py +12 -10
- pyinfra/operations/xbps.py +5 -3
- pyinfra/operations/yum.py +15 -19
- pyinfra/operations/zypper.py +9 -10
- pyinfra/version.py +5 -2
- {pyinfra-3.0.dev0.dist-info → pyinfra-3.0.2.dist-info}/METADATA +51 -58
- pyinfra-3.0.2.dist-info/RECORD +168 -0
- {pyinfra-3.0.dev0.dist-info → pyinfra-3.0.2.dist-info}/WHEEL +1 -1
- {pyinfra-3.0.dev0.dist-info → pyinfra-3.0.2.dist-info}/entry_points.txt +0 -3
- pyinfra_cli/__main__.py +4 -3
- pyinfra_cli/commands.py +3 -2
- pyinfra_cli/exceptions.py +75 -43
- pyinfra_cli/inventory.py +52 -31
- pyinfra_cli/log.py +10 -2
- pyinfra_cli/main.py +88 -65
- pyinfra_cli/prints.py +37 -109
- pyinfra_cli/util.py +15 -10
- tests/test_api/test_api.py +2 -0
- tests/test_api/test_api_arguments.py +9 -9
- tests/test_api/test_api_deploys.py +15 -19
- tests/test_api/test_api_facts.py +4 -5
- tests/test_api/test_api_operations.py +18 -20
- tests/test_api/test_api_util.py +41 -2
- tests/test_cli/test_cli.py +14 -50
- tests/test_cli/test_cli_deploy.py +17 -14
- tests/test_cli/test_cli_exceptions.py +50 -19
- tests/test_cli/test_cli_inventory.py +66 -0
- tests/test_cli/util.py +1 -1
- tests/test_connectors/test_dockerssh.py +11 -8
- tests/test_connectors/test_ssh.py +88 -23
- tests/test_connectors/test_sshuserclient.py +1 -1
- tests/test_connectors/test_terraform.py +11 -8
- tests/test_connectors/test_vagrant.py +6 -6
- pyinfra/connectors/ansible.py +0 -175
- pyinfra/connectors/mech.py +0 -189
- pyinfra/connectors/pyinfrawinrmsession/__init__.py +0 -28
- pyinfra/connectors/winrm.py +0 -312
- 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 -538
- pyinfra-3.0.dev0.dist-info/RECORD +0 -170
- tests/test_connectors/test_ansible.py +0 -64
- tests/test_connectors/test_mech.py +0 -126
- {pyinfra-3.0.dev0.dist-info → pyinfra-3.0.2.dist-info}/LICENSE.md +0 -0
- {pyinfra-3.0.dev0.dist-info → pyinfra-3.0.2.dist-info}/top_level.txt +0 -0
pyinfra/facts/pacman.py
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import shlex
|
|
4
|
+
|
|
1
5
|
from pyinfra.api import FactBase
|
|
2
6
|
|
|
3
7
|
from .util.packaging import parse_packages
|
|
@@ -17,13 +21,14 @@ class PacmanUnpackGroup(FactBase):
|
|
|
17
21
|
]
|
|
18
22
|
"""
|
|
19
23
|
|
|
20
|
-
requires_command
|
|
24
|
+
def requires_command(self, *args, **kwargs) -> str:
|
|
25
|
+
return "pacman"
|
|
21
26
|
|
|
22
27
|
default = list
|
|
23
28
|
|
|
24
|
-
def command(self,
|
|
29
|
+
def command(self, package):
|
|
25
30
|
# Accept failure here (|| true) for invalid/unknown packages
|
|
26
|
-
return 'pacman -S --print-format "%n" {0} || true'.format(
|
|
31
|
+
return 'pacman -S --print-format "%n" {0} || true'.format(shlex.quote(package))
|
|
27
32
|
|
|
28
33
|
def process(self, output):
|
|
29
34
|
return output
|
|
@@ -40,8 +45,11 @@ class PacmanPackages(FactBase):
|
|
|
40
45
|
}
|
|
41
46
|
"""
|
|
42
47
|
|
|
43
|
-
command
|
|
44
|
-
|
|
48
|
+
def command(self) -> str:
|
|
49
|
+
return "pacman -Q"
|
|
50
|
+
|
|
51
|
+
def requires_command(self, *args, **kwargs) -> str:
|
|
52
|
+
return "pacman"
|
|
45
53
|
|
|
46
54
|
default = dict
|
|
47
55
|
|
pyinfra/facts/pip.py
CHANGED
pyinfra/facts/pkg.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from pyinfra.api import FactBase
|
|
2
4
|
|
|
3
5
|
from .util.packaging import parse_packages
|
|
@@ -14,9 +16,11 @@ class PkgPackages(FactBase):
|
|
|
14
16
|
}
|
|
15
17
|
"""
|
|
16
18
|
|
|
17
|
-
command = "pkg info || pkg_info || true"
|
|
18
19
|
regex = r"^([a-zA-Z0-9_\-\+]+)\-([0-9a-z\.]+)"
|
|
19
20
|
default = dict
|
|
20
21
|
|
|
22
|
+
def command(self) -> str:
|
|
23
|
+
return "pkg info || pkg_info || true"
|
|
24
|
+
|
|
21
25
|
def process(self, output):
|
|
22
26
|
return parse_packages(self.regex, output)
|
pyinfra/facts/pkgin.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from pyinfra.api import FactBase
|
|
2
4
|
|
|
3
5
|
from .util.packaging import parse_packages
|
|
@@ -16,8 +18,11 @@ class PkginPackages(FactBase):
|
|
|
16
18
|
}
|
|
17
19
|
"""
|
|
18
20
|
|
|
19
|
-
command
|
|
20
|
-
|
|
21
|
+
def command(self) -> str:
|
|
22
|
+
return "pkgin list"
|
|
23
|
+
|
|
24
|
+
def requires_command(self) -> str:
|
|
25
|
+
return "pkgin"
|
|
21
26
|
|
|
22
27
|
default = dict
|
|
23
28
|
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pyinfra.api import FactBase, MaskString, QuoteString, StringCommand
|
|
4
|
+
from pyinfra.api.util import try_int
|
|
5
|
+
|
|
6
|
+
from .util.databases import parse_columns_and_rows
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def make_psql_command(
|
|
10
|
+
database: str | None = None,
|
|
11
|
+
user: str | None = None,
|
|
12
|
+
password: str | None = None,
|
|
13
|
+
host: str | None = None,
|
|
14
|
+
port: str | int | None = None,
|
|
15
|
+
executable="psql",
|
|
16
|
+
) -> StringCommand:
|
|
17
|
+
target_bits: list[str] = []
|
|
18
|
+
|
|
19
|
+
if password:
|
|
20
|
+
target_bits.append(MaskString('PGPASSWORD="{0}"'.format(password)))
|
|
21
|
+
|
|
22
|
+
target_bits.append(executable)
|
|
23
|
+
|
|
24
|
+
if database:
|
|
25
|
+
target_bits.append("-d {0}".format(database))
|
|
26
|
+
|
|
27
|
+
if user:
|
|
28
|
+
target_bits.append("-U {0}".format(user))
|
|
29
|
+
|
|
30
|
+
if host:
|
|
31
|
+
target_bits.append("-h {0}".format(host))
|
|
32
|
+
|
|
33
|
+
if port:
|
|
34
|
+
target_bits.append("-p {0}".format(port))
|
|
35
|
+
|
|
36
|
+
return StringCommand(*target_bits)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def make_execute_psql_command(command, **psql_kwargs):
|
|
40
|
+
return StringCommand(
|
|
41
|
+
make_psql_command(**psql_kwargs),
|
|
42
|
+
"-Ac",
|
|
43
|
+
QuoteString(command), # quote this whole item as a single shell argument
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class PostgresFactBase(FactBase):
|
|
48
|
+
abstract = True
|
|
49
|
+
|
|
50
|
+
psql_command: str
|
|
51
|
+
|
|
52
|
+
def requires_command(self, *args, **kwargs):
|
|
53
|
+
return "psql"
|
|
54
|
+
|
|
55
|
+
def command(
|
|
56
|
+
self,
|
|
57
|
+
psql_user=None,
|
|
58
|
+
psql_password=None,
|
|
59
|
+
psql_host=None,
|
|
60
|
+
psql_port=None,
|
|
61
|
+
):
|
|
62
|
+
return make_execute_psql_command(
|
|
63
|
+
self.psql_command,
|
|
64
|
+
user=psql_user,
|
|
65
|
+
password=psql_password,
|
|
66
|
+
host=psql_host,
|
|
67
|
+
port=psql_port,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class PostgresRoles(PostgresFactBase):
|
|
72
|
+
"""
|
|
73
|
+
Returns a dict of PostgreSQL roles and data:
|
|
74
|
+
|
|
75
|
+
.. code:: python
|
|
76
|
+
|
|
77
|
+
{
|
|
78
|
+
"pyinfra": {
|
|
79
|
+
"super": true,
|
|
80
|
+
"createrole": false,
|
|
81
|
+
"createdb": false,
|
|
82
|
+
...
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
default = dict
|
|
88
|
+
psql_command = "SELECT * FROM pg_catalog.pg_roles"
|
|
89
|
+
|
|
90
|
+
def process(self, output):
|
|
91
|
+
# Remove the last line of the output (row count)
|
|
92
|
+
output = output[:-1]
|
|
93
|
+
rows = parse_columns_and_rows(
|
|
94
|
+
output,
|
|
95
|
+
"|",
|
|
96
|
+
# Remove the "rol" prefix on column names
|
|
97
|
+
remove_column_prefix="rol",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
users = {}
|
|
101
|
+
|
|
102
|
+
for details in rows:
|
|
103
|
+
for key, value in list(details.items()):
|
|
104
|
+
if key in ("oid", "connlimit"):
|
|
105
|
+
details[key] = try_int(value)
|
|
106
|
+
|
|
107
|
+
if key in (
|
|
108
|
+
"super",
|
|
109
|
+
"inherit",
|
|
110
|
+
"createrole",
|
|
111
|
+
"createdb",
|
|
112
|
+
"canlogin",
|
|
113
|
+
"replication",
|
|
114
|
+
"bypassrls",
|
|
115
|
+
):
|
|
116
|
+
details[key] = value == "t"
|
|
117
|
+
|
|
118
|
+
users[details.pop("name")] = details
|
|
119
|
+
|
|
120
|
+
return users
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class PostgresDatabases(PostgresFactBase):
|
|
124
|
+
"""
|
|
125
|
+
Returns a dict of PostgreSQL databases and metadata:
|
|
126
|
+
|
|
127
|
+
.. code:: python
|
|
128
|
+
|
|
129
|
+
{
|
|
130
|
+
"pyinfra_stuff": {
|
|
131
|
+
"encoding": "UTF8",
|
|
132
|
+
"collate": "en_US.UTF-8",
|
|
133
|
+
"ctype": "en_US.UTF-8",
|
|
134
|
+
...
|
|
135
|
+
},
|
|
136
|
+
}
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
default = dict
|
|
140
|
+
psql_command = "SELECT pg_catalog.pg_encoding_to_char(encoding), * FROM pg_catalog.pg_database"
|
|
141
|
+
|
|
142
|
+
def process(self, output):
|
|
143
|
+
# Remove the last line of the output (row count)
|
|
144
|
+
output = output[:-1]
|
|
145
|
+
rows = parse_columns_and_rows(
|
|
146
|
+
output,
|
|
147
|
+
"|",
|
|
148
|
+
# Remove the "dat" prefix on column names
|
|
149
|
+
remove_column_prefix="dat",
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
databases = {}
|
|
153
|
+
|
|
154
|
+
for details in rows:
|
|
155
|
+
details["encoding"] = details.pop("pg_encoding_to_char")
|
|
156
|
+
|
|
157
|
+
for key, value in list(details.items()):
|
|
158
|
+
if key.endswith("id") or key in (
|
|
159
|
+
"dba",
|
|
160
|
+
"tablespace",
|
|
161
|
+
"connlimit",
|
|
162
|
+
):
|
|
163
|
+
details[key] = try_int(value)
|
|
164
|
+
|
|
165
|
+
if key in ("istemplate", "allowconn"):
|
|
166
|
+
details[key] = value == "t"
|
|
167
|
+
|
|
168
|
+
databases[details.pop("name")] = details
|
|
169
|
+
|
|
170
|
+
return databases
|
pyinfra/facts/postgresql.py
CHANGED
|
@@ -1,168 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
from pyinfra.api.util import try_int
|
|
3
|
+
from .postgres import PostgresDatabases, PostgresRoles
|
|
5
4
|
|
|
6
|
-
from .util.databases import parse_columns_and_rows
|
|
7
5
|
|
|
6
|
+
class PostgresqlRoles(PostgresRoles):
|
|
7
|
+
deprecated = True
|
|
8
8
|
|
|
9
|
-
def make_psql_command(
|
|
10
|
-
database=None,
|
|
11
|
-
user=None,
|
|
12
|
-
password=None,
|
|
13
|
-
host=None,
|
|
14
|
-
port=None,
|
|
15
|
-
executable="psql",
|
|
16
|
-
):
|
|
17
|
-
target_bits: list[str] = []
|
|
18
9
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
target_bits.append(executable)
|
|
23
|
-
|
|
24
|
-
if database:
|
|
25
|
-
target_bits.append("-d {0}".format(database))
|
|
26
|
-
|
|
27
|
-
if user:
|
|
28
|
-
target_bits.append("-U {0}".format(user))
|
|
29
|
-
|
|
30
|
-
if host:
|
|
31
|
-
target_bits.append("-h {0}".format(host))
|
|
32
|
-
|
|
33
|
-
if port:
|
|
34
|
-
target_bits.append("-p {0}".format(port))
|
|
35
|
-
|
|
36
|
-
return StringCommand(*target_bits)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def make_execute_psql_command(command, **psql_kwargs):
|
|
40
|
-
return StringCommand(
|
|
41
|
-
make_psql_command(**psql_kwargs),
|
|
42
|
-
"-Ac",
|
|
43
|
-
QuoteString(command), # quote this whole item as a single shell argument
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
class PostgresqlFactBase(FactBase):
|
|
48
|
-
abstract = True
|
|
49
|
-
|
|
50
|
-
psql_command: str
|
|
51
|
-
requires_command = "psql"
|
|
52
|
-
|
|
53
|
-
def command(
|
|
54
|
-
self,
|
|
55
|
-
psql_user=None,
|
|
56
|
-
psql_password=None,
|
|
57
|
-
psql_host=None,
|
|
58
|
-
psql_port=None,
|
|
59
|
-
):
|
|
60
|
-
return make_execute_psql_command(
|
|
61
|
-
self.psql_command,
|
|
62
|
-
user=psql_user,
|
|
63
|
-
password=psql_password,
|
|
64
|
-
host=psql_host,
|
|
65
|
-
port=psql_port,
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
class PostgresqlRoles(PostgresqlFactBase):
|
|
70
|
-
"""
|
|
71
|
-
Returns a dict of PostgreSQL roles and data:
|
|
72
|
-
|
|
73
|
-
.. code:: python
|
|
74
|
-
|
|
75
|
-
{
|
|
76
|
-
"pyinfra": {
|
|
77
|
-
"super": true,
|
|
78
|
-
"createrole": false,
|
|
79
|
-
"createdb": false,
|
|
80
|
-
...
|
|
81
|
-
},
|
|
82
|
-
}
|
|
83
|
-
"""
|
|
84
|
-
|
|
85
|
-
default = dict
|
|
86
|
-
psql_command = "SELECT * FROM pg_catalog.pg_roles"
|
|
87
|
-
|
|
88
|
-
def process(self, output):
|
|
89
|
-
# Remove the last line of the output (row count)
|
|
90
|
-
output = output[:-1]
|
|
91
|
-
rows = parse_columns_and_rows(
|
|
92
|
-
output,
|
|
93
|
-
"|",
|
|
94
|
-
# Remove the "rol" prefix on column names
|
|
95
|
-
remove_column_prefix="rol",
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
users = {}
|
|
99
|
-
|
|
100
|
-
for details in rows:
|
|
101
|
-
for key, value in list(details.items()):
|
|
102
|
-
if key in ("oid", "connlimit"):
|
|
103
|
-
details[key] = try_int(value)
|
|
104
|
-
|
|
105
|
-
if key in (
|
|
106
|
-
"super",
|
|
107
|
-
"inherit",
|
|
108
|
-
"createrole",
|
|
109
|
-
"createdb",
|
|
110
|
-
"canlogin",
|
|
111
|
-
"replication",
|
|
112
|
-
"bypassrls",
|
|
113
|
-
):
|
|
114
|
-
details[key] = value == "t"
|
|
115
|
-
|
|
116
|
-
users[details.pop("name")] = details
|
|
117
|
-
|
|
118
|
-
return users
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
class PostgresqlDatabases(PostgresqlFactBase):
|
|
122
|
-
"""
|
|
123
|
-
Returns a dict of PostgreSQL databases and metadata:
|
|
124
|
-
|
|
125
|
-
.. code:: python
|
|
126
|
-
|
|
127
|
-
{
|
|
128
|
-
"pyinfra_stuff": {
|
|
129
|
-
"encoding": "UTF8",
|
|
130
|
-
"collate": "en_US.UTF-8",
|
|
131
|
-
"ctype": "en_US.UTF-8",
|
|
132
|
-
...
|
|
133
|
-
},
|
|
134
|
-
}
|
|
135
|
-
"""
|
|
136
|
-
|
|
137
|
-
default = dict
|
|
138
|
-
psql_command = "SELECT pg_catalog.pg_encoding_to_char(encoding), * FROM pg_catalog.pg_database"
|
|
139
|
-
|
|
140
|
-
def process(self, output):
|
|
141
|
-
# Remove the last line of the output (row count)
|
|
142
|
-
output = output[:-1]
|
|
143
|
-
rows = parse_columns_and_rows(
|
|
144
|
-
output,
|
|
145
|
-
"|",
|
|
146
|
-
# Remove the "dat" prefix on column names
|
|
147
|
-
remove_column_prefix="dat",
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
databases = {}
|
|
151
|
-
|
|
152
|
-
for details in rows:
|
|
153
|
-
details["encoding"] = details.pop("pg_encoding_to_char")
|
|
154
|
-
|
|
155
|
-
for key, value in list(details.items()):
|
|
156
|
-
if key.endswith("id") or key in (
|
|
157
|
-
"dba",
|
|
158
|
-
"tablespace",
|
|
159
|
-
"connlimit",
|
|
160
|
-
):
|
|
161
|
-
details[key] = try_int(value)
|
|
162
|
-
|
|
163
|
-
if key in ("istemplate", "allowconn"):
|
|
164
|
-
details[key] = value == "t"
|
|
165
|
-
|
|
166
|
-
databases[details.pop("name")] = details
|
|
167
|
-
|
|
168
|
-
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,8 +22,11 @@ class RpmPackages(FactBase):
|
|
|
19
22
|
}
|
|
20
23
|
"""
|
|
21
24
|
|
|
22
|
-
command
|
|
23
|
-
|
|
25
|
+
def command(self) -> str:
|
|
26
|
+
return "rpm --queryformat {0} -qa".format(shlex.quote(rpm_query_format))
|
|
27
|
+
|
|
28
|
+
def requires_command(self) -> str:
|
|
29
|
+
return "rpm"
|
|
24
30
|
|
|
25
31
|
default = dict
|
|
26
32
|
|
|
@@ -40,14 +46,15 @@ class RpmPackage(FactBase):
|
|
|
40
46
|
}
|
|
41
47
|
"""
|
|
42
48
|
|
|
43
|
-
requires_command
|
|
49
|
+
def requires_command(self, package) -> str:
|
|
50
|
+
return "rpm"
|
|
44
51
|
|
|
45
|
-
def command(self,
|
|
52
|
+
def command(self, package) -> str:
|
|
46
53
|
return (
|
|
47
|
-
|
|
54
|
+
"rpm --queryformat {0} -q {1} || "
|
|
48
55
|
"! test -e {1} || "
|
|
49
|
-
|
|
50
|
-
).format(rpm_query_format,
|
|
56
|
+
"rpm --queryformat {0} -qp {1} 2> /dev/null"
|
|
57
|
+
).format(shlex.quote(rpm_query_format), shlex.quote(package))
|
|
51
58
|
|
|
52
59
|
def process(self, output):
|
|
53
60
|
for line in output:
|
|
@@ -66,18 +73,17 @@ class RpmPackageProvides(FactBase):
|
|
|
66
73
|
|
|
67
74
|
default = list
|
|
68
75
|
|
|
69
|
-
requires_command
|
|
76
|
+
def requires_command(self, *args, **kwargs) -> str:
|
|
77
|
+
return "repoquery"
|
|
70
78
|
|
|
71
|
-
|
|
72
|
-
def command(name):
|
|
79
|
+
def command(self, package):
|
|
73
80
|
# Accept failure here (|| true) for invalid/unknown packages
|
|
74
|
-
return
|
|
75
|
-
rpm_query_format,
|
|
76
|
-
|
|
81
|
+
return "repoquery --queryformat {0} --whatprovides {1} || true".format(
|
|
82
|
+
shlex.quote(rpm_query_format),
|
|
83
|
+
shlex.quote(package),
|
|
77
84
|
)
|
|
78
85
|
|
|
79
|
-
|
|
80
|
-
def process(output):
|
|
86
|
+
def process(self, output):
|
|
81
87
|
packages = []
|
|
82
88
|
|
|
83
89
|
for line in output:
|
pyinfra/facts/runit.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
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
|
+
default = dict
|
|
22
|
+
|
|
23
|
+
def requires_command(self, *args, **kwargs) -> str:
|
|
24
|
+
return "sv"
|
|
25
|
+
|
|
26
|
+
def command(self, service=None, svdir="/var/service") -> str:
|
|
27
|
+
if service is None:
|
|
28
|
+
return (
|
|
29
|
+
'export SVDIR="{0}" && '
|
|
30
|
+
'cd "$SVDIR" && find * -maxdepth 0 -exec sv status {{}} + 2>/dev/null'
|
|
31
|
+
).format(svdir)
|
|
32
|
+
else:
|
|
33
|
+
return 'SVDIR="{0}" sv status "{1}"'.format(svdir, service)
|
|
34
|
+
|
|
35
|
+
def process(self, output):
|
|
36
|
+
services = {}
|
|
37
|
+
for line in output:
|
|
38
|
+
statusstr, service, _ = line.split(sep=": ", maxsplit=2)
|
|
39
|
+
status = None
|
|
40
|
+
|
|
41
|
+
if statusstr == "run":
|
|
42
|
+
status = True
|
|
43
|
+
elif statusstr == "down":
|
|
44
|
+
status = False
|
|
45
|
+
# another observable state is "fail"
|
|
46
|
+
# report as ``None`` for now
|
|
47
|
+
|
|
48
|
+
services[service] = status
|
|
49
|
+
|
|
50
|
+
return services
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class RunitManaged(FactBase):
|
|
54
|
+
"""
|
|
55
|
+
Returns a set of all services managed by runit
|
|
56
|
+
|
|
57
|
+
+ service: optionally check only for a single service
|
|
58
|
+
+ svdir: alternative ``SVDIR``
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
default = set
|
|
62
|
+
|
|
63
|
+
def command(self, service=None, svdir="/var/service"):
|
|
64
|
+
if service is None:
|
|
65
|
+
return 'cd "{0}" && find -mindepth 1 -maxdepth 1 -type l -printf "%f\n"'.format(svdir)
|
|
66
|
+
else:
|
|
67
|
+
return 'cd "{0}" && test -h "{1}" && echo "{1}" || true'.format(svdir, service)
|
|
68
|
+
|
|
69
|
+
def process(self, output):
|
|
70
|
+
return set(output)
|
pyinfra/facts/selinux.py
CHANGED
|
@@ -14,7 +14,9 @@ class SEBoolean(FactBase):
|
|
|
14
14
|
If ``boolean`` does not exist, ``SEBoolean`` returns the empty string.
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
-
requires_command
|
|
17
|
+
def requires_command(self, boolean) -> str:
|
|
18
|
+
return "getsebool"
|
|
19
|
+
|
|
18
20
|
default = str
|
|
19
21
|
|
|
20
22
|
def command(self, boolean):
|
|
@@ -60,9 +62,11 @@ class FileContextMapping(FactBase):
|
|
|
60
62
|
Note: This fact requires root privileges.
|
|
61
63
|
"""
|
|
62
64
|
|
|
63
|
-
requires_command = "semanage"
|
|
64
65
|
default = dict
|
|
65
66
|
|
|
67
|
+
def requires_command(self, target) -> str:
|
|
68
|
+
return "semanage"
|
|
69
|
+
|
|
66
70
|
def command(self, target):
|
|
67
71
|
return "set -o pipefail && semanage fcontext -n -l | (grep '^{0}' || true)".format(target)
|
|
68
72
|
|
|
@@ -87,11 +91,13 @@ class SEPorts(FactBase):
|
|
|
87
91
|
}
|
|
88
92
|
"""
|
|
89
93
|
|
|
90
|
-
requires_command = "semanage"
|
|
91
94
|
default = dict
|
|
92
95
|
# example output: amqp_port_t tcp 15672, 5671-5672 # noqa: SC100
|
|
93
96
|
_regex = re.compile(r"^([\w_]+)\s+(\w+)\s+([\w\-,\s]+)$")
|
|
94
97
|
|
|
98
|
+
def requires_command(self) -> str:
|
|
99
|
+
return "semanage"
|
|
100
|
+
|
|
95
101
|
def command(self):
|
|
96
102
|
return "semanage port -ln"
|
|
97
103
|
|
|
@@ -122,9 +128,11 @@ class SEPort(FactBase):
|
|
|
122
128
|
Note: ``policycoreutils-dev`` must be installed for this to work.
|
|
123
129
|
"""
|
|
124
130
|
|
|
125
|
-
requires_command = "sepolicy"
|
|
126
131
|
default = str
|
|
127
132
|
|
|
133
|
+
def requires_command(self, protocol, port) -> str:
|
|
134
|
+
return "sepolicy"
|
|
135
|
+
|
|
128
136
|
def command(self, protocol, port):
|
|
129
137
|
return "(sepolicy network -p {0} 2>/dev/null || true) | grep {1}".format(port, protocol)
|
|
130
138
|
|