pyinfra 3.0b0__py2.py3-none-any.whl → 3.0b2__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 +12 -5
- pyinfra/api/arguments_typed.py +19 -6
- pyinfra/api/command.py +5 -3
- pyinfra/api/config.py +115 -13
- pyinfra/api/connectors.py +5 -2
- pyinfra/api/exceptions.py +19 -0
- pyinfra/api/facts.py +34 -33
- pyinfra/api/host.py +51 -12
- pyinfra/api/inventory.py +4 -0
- pyinfra/api/operation.py +88 -42
- pyinfra/api/operations.py +10 -11
- pyinfra/api/state.py +11 -2
- pyinfra/api/util.py +24 -16
- pyinfra/connectors/base.py +4 -7
- pyinfra/connectors/chroot.py +5 -6
- pyinfra/connectors/docker.py +13 -19
- pyinfra/connectors/dockerssh.py +5 -4
- pyinfra/connectors/local.py +7 -7
- pyinfra/connectors/ssh.py +46 -25
- pyinfra/connectors/terraform.py +9 -6
- pyinfra/connectors/util.py +7 -8
- pyinfra/connectors/vagrant.py +11 -10
- pyinfra/context.py +1 -0
- 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 +3 -1
- pyinfra/facts/deb.py +9 -4
- pyinfra/facts/dnf.py +2 -0
- pyinfra/facts/docker.py +2 -0
- pyinfra/facts/files.py +2 -0
- pyinfra/facts/gem.py +2 -0
- pyinfra/facts/gpg.py +2 -0
- pyinfra/facts/hardware.py +30 -22
- pyinfra/facts/launchd.py +2 -0
- pyinfra/facts/lxd.py +2 -0
- pyinfra/facts/mysql.py +12 -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 +5 -162
- pyinfra/facts/rpm.py +12 -9
- pyinfra/facts/server.py +10 -13
- pyinfra/facts/snap.py +2 -0
- pyinfra/facts/systemd.py +28 -10
- pyinfra/facts/upstart.py +2 -0
- pyinfra/facts/util/packaging.py +3 -2
- 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/operations/apk.py +3 -1
- pyinfra/operations/apt.py +16 -18
- pyinfra/operations/brew.py +10 -8
- pyinfra/operations/bsdinit.py +5 -3
- pyinfra/operations/cargo.py +3 -1
- pyinfra/operations/choco.py +3 -1
- pyinfra/operations/dnf.py +15 -19
- pyinfra/operations/files.py +86 -69
- pyinfra/operations/gem.py +3 -1
- pyinfra/operations/git.py +18 -16
- pyinfra/operations/iptables.py +33 -25
- pyinfra/operations/launchd.py +5 -6
- pyinfra/operations/lxd.py +7 -4
- pyinfra/operations/mysql.py +57 -53
- pyinfra/operations/npm.py +8 -1
- pyinfra/operations/openrc.py +5 -3
- pyinfra/operations/pacman.py +4 -5
- pyinfra/operations/pip.py +16 -9
- pyinfra/operations/pkg.py +3 -1
- pyinfra/operations/pkgin.py +3 -1
- pyinfra/operations/postgres.py +349 -0
- pyinfra/operations/postgresql.py +18 -335
- pyinfra/operations/puppet.py +3 -1
- pyinfra/operations/python.py +7 -3
- pyinfra/operations/selinux.py +42 -16
- pyinfra/operations/server.py +48 -43
- pyinfra/operations/snap.py +3 -1
- pyinfra/operations/ssh.py +12 -10
- pyinfra/operations/systemd.py +13 -9
- pyinfra/operations/sysvinit.py +6 -4
- pyinfra/operations/upstart.py +5 -3
- pyinfra/operations/util/files.py +24 -16
- pyinfra/operations/util/packaging.py +53 -37
- pyinfra/operations/util/service.py +18 -13
- pyinfra/operations/vzctl.py +12 -10
- pyinfra/operations/xbps.py +3 -1
- pyinfra/operations/yum.py +14 -18
- pyinfra/operations/zypper.py +8 -9
- pyinfra/version.py +5 -2
- {pyinfra-3.0b0.dist-info → pyinfra-3.0b2.dist-info}/METADATA +31 -29
- pyinfra-3.0b2.dist-info/RECORD +163 -0
- {pyinfra-3.0b0.dist-info → pyinfra-3.0b2.dist-info}/WHEEL +1 -1
- pyinfra_cli/commands.py +3 -2
- pyinfra_cli/inventory.py +38 -19
- pyinfra_cli/main.py +2 -0
- pyinfra_cli/prints.py +27 -105
- pyinfra_cli/util.py +3 -1
- tests/test_api/test_api_deploys.py +5 -5
- tests/test_api/test_api_operations.py +5 -5
- tests/test_connectors/test_ssh.py +105 -0
- tests/test_connectors/test_terraform.py +11 -8
- tests/test_connectors/test_vagrant.py +6 -6
- pyinfra-3.0b0.dist-info/RECORD +0 -162
- pyinfra_cli/inventory_dsl.py +0 -23
- {pyinfra-3.0b0.dist-info → pyinfra-3.0b2.dist-info}/LICENSE.md +0 -0
- {pyinfra-3.0b0.dist-info → pyinfra-3.0b2.dist-info}/entry_points.txt +0 -0
- {pyinfra-3.0b0.dist-info → pyinfra-3.0b2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,168 @@
|
|
|
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
|
+
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 PostgresRoles(PostgresFactBase):
|
|
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 PostgresDatabases(PostgresFactBase):
|
|
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
|
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,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/server.py
CHANGED
|
@@ -5,7 +5,7 @@ import re
|
|
|
5
5
|
import shutil
|
|
6
6
|
from datetime import datetime
|
|
7
7
|
from tempfile import mkdtemp
|
|
8
|
-
from typing import Dict, List,
|
|
8
|
+
from typing import Dict, List, Optional, Union
|
|
9
9
|
|
|
10
10
|
from dateutil.parser import parse as parse_date
|
|
11
11
|
from distro import distro
|
|
@@ -25,12 +25,14 @@ class User(FactBase):
|
|
|
25
25
|
command = "echo $USER"
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
class Home(FactBase):
|
|
28
|
+
class Home(FactBase[Optional[str]]):
|
|
29
29
|
"""
|
|
30
|
-
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.
|
|
31
31
|
"""
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
@staticmethod
|
|
34
|
+
def command(user=""):
|
|
35
|
+
return f"echo ~{user}"
|
|
34
36
|
|
|
35
37
|
|
|
36
38
|
class Path(FactBase):
|
|
@@ -348,8 +350,7 @@ class Groups(FactBase[List[str]]):
|
|
|
348
350
|
command = "cat /etc/group"
|
|
349
351
|
default = list
|
|
350
352
|
|
|
351
|
-
|
|
352
|
-
def process(output) -> list[str]:
|
|
353
|
+
def process(self, output) -> list[str]:
|
|
353
354
|
groups: list[str] = []
|
|
354
355
|
|
|
355
356
|
for line in output:
|
|
@@ -359,9 +360,6 @@ class Groups(FactBase[List[str]]):
|
|
|
359
360
|
return groups
|
|
360
361
|
|
|
361
362
|
|
|
362
|
-
CrontabCommand = NewType("CrontabCommand", int)
|
|
363
|
-
|
|
364
|
-
|
|
365
363
|
class CrontabDict(TypedDict):
|
|
366
364
|
minute: NotRequired[Union[int, str]]
|
|
367
365
|
hour: NotRequired[Union[int, str]]
|
|
@@ -372,7 +370,7 @@ class CrontabDict(TypedDict):
|
|
|
372
370
|
special_time: NotRequired[str]
|
|
373
371
|
|
|
374
372
|
|
|
375
|
-
class Crontab(FactBase[Dict[
|
|
373
|
+
class Crontab(FactBase[Dict[str, CrontabDict]]):
|
|
376
374
|
"""
|
|
377
375
|
Returns a dictionary of cron command -> execution time.
|
|
378
376
|
|
|
@@ -402,9 +400,8 @@ class Crontab(FactBase[Dict[CrontabCommand, CrontabDict]]):
|
|
|
402
400
|
return "crontab -l -u {0} || true".format(user)
|
|
403
401
|
return "crontab -l || true"
|
|
404
402
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
crons: dict[Command, CrontabDict] = {}
|
|
403
|
+
def process(self, output):
|
|
404
|
+
crons: dict[str, CrontabDict] = {}
|
|
408
405
|
current_comments = []
|
|
409
406
|
|
|
410
407
|
for line in output:
|
pyinfra/facts/snap.py
CHANGED
pyinfra/facts/systemd.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import re
|
|
2
|
-
from typing import Dict
|
|
4
|
+
from typing import Dict, Iterable
|
|
3
5
|
|
|
4
|
-
from pyinfra.api import FactBase
|
|
6
|
+
from pyinfra.api import FactBase, FactTypeError, QuoteString, StringCommand
|
|
5
7
|
|
|
6
8
|
# Valid unit names consist of a "name prefix" and a dot and a suffix specifying the unit type.
|
|
7
9
|
# The "unit prefix" must consist of one or more valid characters
|
|
@@ -22,18 +24,16 @@ SYSTEMD_UNIT_NAME_REGEX = (
|
|
|
22
24
|
|
|
23
25
|
def _make_systemctl_cmd(user_mode=False, machine=None, user_name=None):
|
|
24
26
|
# base command for normal and user mode
|
|
25
|
-
systemctl_cmd = "systemctl --user" if user_mode else "systemctl"
|
|
27
|
+
systemctl_cmd = ["systemctl --user"] if user_mode else ["systemctl"]
|
|
26
28
|
|
|
27
29
|
# add user and machine flag if given in args
|
|
28
30
|
if machine is not None:
|
|
29
31
|
if user_name is not None:
|
|
30
|
-
|
|
32
|
+
systemctl_cmd.append("--machine={1}@{0}".format(machine, user_name))
|
|
31
33
|
else:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
systemctl_cmd = "{0} {1}".format(systemctl_cmd, machine_opt)
|
|
34
|
+
systemctl_cmd.append("--machine={0}".format(machine))
|
|
35
35
|
|
|
36
|
-
return systemctl_cmd
|
|
36
|
+
return StringCommand(*systemctl_cmd)
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
class SystemdStatus(FactBase[Dict[str, bool]]):
|
|
@@ -59,14 +59,32 @@ class SystemdStatus(FactBase[Dict[str, bool]]):
|
|
|
59
59
|
state_key = "SubState"
|
|
60
60
|
state_values = ["running", "waiting", "exited"]
|
|
61
61
|
|
|
62
|
-
def command(self, user_mode=False, machine=None, user_name=None):
|
|
62
|
+
def command(self, user_mode=False, machine=None, user_name=None, services=None):
|
|
63
63
|
fact_cmd = _make_systemctl_cmd(
|
|
64
64
|
user_mode=user_mode,
|
|
65
65
|
machine=machine,
|
|
66
66
|
user_name=user_name,
|
|
67
67
|
)
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
if services is None:
|
|
70
|
+
service_strs = [QuoteString("*")]
|
|
71
|
+
elif isinstance(services, str):
|
|
72
|
+
service_strs = [QuoteString(services)]
|
|
73
|
+
elif isinstance(services, Iterable):
|
|
74
|
+
service_strs = [QuoteString(s) for s in services]
|
|
75
|
+
else:
|
|
76
|
+
raise FactTypeError(f"Invalid type passed for services argument: {type(services)}")
|
|
77
|
+
|
|
78
|
+
return StringCommand(
|
|
79
|
+
fact_cmd,
|
|
80
|
+
"show",
|
|
81
|
+
"--all",
|
|
82
|
+
"--property",
|
|
83
|
+
"Id",
|
|
84
|
+
"--property",
|
|
85
|
+
self.state_key,
|
|
86
|
+
*service_strs,
|
|
87
|
+
)
|
|
70
88
|
|
|
71
89
|
def process(self, output) -> Dict[str, bool]:
|
|
72
90
|
services: Dict[str, bool] = {}
|
pyinfra/facts/upstart.py
CHANGED
pyinfra/facts/util/packaging.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
+
from typing import Iterable
|
|
4
5
|
|
|
5
6
|
|
|
6
|
-
def parse_packages(regex, output):
|
|
7
|
+
def parse_packages(regex: str, output: Iterable[str]) -> dict[str, set[str]]:
|
|
7
8
|
packages: dict[str, set[str]] = {}
|
|
8
9
|
|
|
9
10
|
for line in output:
|
|
@@ -34,7 +35,7 @@ def _parse_yum_or_zypper_repositories(output):
|
|
|
34
35
|
current_repo["name"] = line[1:-1]
|
|
35
36
|
|
|
36
37
|
if current_repo and "=" in line:
|
|
37
|
-
key, value =
|
|
38
|
+
key, value = re.split(r"\s*=\s*", line, maxsplit=1)
|
|
38
39
|
current_repo[key] = value
|
|
39
40
|
|
|
40
41
|
if current_repo:
|
pyinfra/facts/vzctl.py
CHANGED
pyinfra/facts/xbps.py
CHANGED
pyinfra/facts/yum.py
CHANGED
pyinfra/facts/zypper.py
CHANGED
pyinfra/operations/apk.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Manage apk packages.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
5
7
|
from pyinfra import host
|
|
6
8
|
from pyinfra.api import operation
|
|
7
9
|
from pyinfra.facts.apk import ApkPackages
|
|
@@ -40,7 +42,7 @@ _update = update._inner # noqa: E305
|
|
|
40
42
|
|
|
41
43
|
@operation()
|
|
42
44
|
def packages(
|
|
43
|
-
packages=None,
|
|
45
|
+
packages: str | list[str] | None = None,
|
|
44
46
|
present=True,
|
|
45
47
|
latest=False,
|
|
46
48
|
update=False,
|