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/operations/postgresql.py
CHANGED
|
@@ -1,391 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
The PostgreSQL modules manage PostgreSQL databases, users and privileges.
|
|
1
|
+
from __future__ import annotations
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
from pyinfra.api import operation
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
+ ``psql_user``: the username to connect to postgresql to
|
|
8
|
-
+ ``psql_password``: the password for the connecting user
|
|
9
|
-
+ ``psql_host``: the hostname of the server to connect to
|
|
10
|
-
+ ``psql_port``: the port of the server to connect to
|
|
5
|
+
from . import postgres
|
|
11
6
|
|
|
12
|
-
See example/postgresql.py for detailed example
|
|
13
7
|
|
|
14
|
-
""
|
|
8
|
+
@operation(is_idempotent=False, is_deprecated=True, deprecated_for="postgres.sql")
|
|
9
|
+
def sql(*args, **kwargs):
|
|
10
|
+
yield from postgres.sql._inner(*args, **kwargs)
|
|
15
11
|
|
|
16
|
-
from pyinfra import host, logger
|
|
17
|
-
from pyinfra.api import MaskString, StringCommand, operation
|
|
18
|
-
from pyinfra.facts.postgresql import (
|
|
19
|
-
PostgresqlDatabases,
|
|
20
|
-
PostgresqlRoles,
|
|
21
|
-
make_execute_psql_command,
|
|
22
|
-
make_psql_command,
|
|
23
|
-
)
|
|
24
12
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"postgresql_host": "psql_host",
|
|
29
|
-
"postgresql_port": "psql_port",
|
|
30
|
-
}
|
|
13
|
+
@operation(is_idempotent=False, is_deprecated=True, deprecated_for="postgres.role")
|
|
14
|
+
def role(*args, **kwargs):
|
|
15
|
+
yield from postgres.role._inner(*args, **kwargs)
|
|
31
16
|
|
|
32
17
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if legacy_key in kwargs:
|
|
37
|
-
kwargs[key] = kwargs.pop(legacy_key)
|
|
38
|
-
logger.warning(
|
|
39
|
-
(
|
|
40
|
-
f"The `{legacy_key}` has been replaced "
|
|
41
|
-
f"by `{key}` in `postgresql.*` operations."
|
|
42
|
-
),
|
|
43
|
-
)
|
|
44
|
-
return func(*args, **kwargs)
|
|
18
|
+
@operation(is_idempotent=False, is_deprecated=True)
|
|
19
|
+
def database(*args, **kwargs):
|
|
20
|
+
yield from postgres.database._inner(*args, **kwargs)
|
|
45
21
|
|
|
46
|
-
decorated_func._pyinfra_op = func
|
|
47
|
-
return decorated_func
|
|
48
22
|
|
|
23
|
+
@operation(is_idempotent=False, is_deprecated=True)
|
|
24
|
+
def dump(*args, **kwargs):
|
|
25
|
+
yield from postgres.dump._inner(*args, **kwargs)
|
|
49
26
|
|
|
50
|
-
@operation(is_idempotent=False)
|
|
51
|
-
@_translate_legacy_args
|
|
52
|
-
def sql(
|
|
53
|
-
sql,
|
|
54
|
-
database=None,
|
|
55
|
-
# Details for speaking to PostgreSQL via `psql` CLI
|
|
56
|
-
psql_user=None,
|
|
57
|
-
psql_password=None,
|
|
58
|
-
psql_host=None,
|
|
59
|
-
psql_port=None,
|
|
60
|
-
):
|
|
61
|
-
"""
|
|
62
|
-
Execute arbitrary SQL against PostgreSQL.
|
|
63
27
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
"""
|
|
68
|
-
|
|
69
|
-
yield make_execute_psql_command(
|
|
70
|
-
sql,
|
|
71
|
-
database=database,
|
|
72
|
-
user=psql_user,
|
|
73
|
-
password=psql_password,
|
|
74
|
-
host=psql_host,
|
|
75
|
-
port=psql_port,
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
@operation
|
|
80
|
-
@_translate_legacy_args
|
|
81
|
-
def role(
|
|
82
|
-
role,
|
|
83
|
-
present=True,
|
|
84
|
-
password=None,
|
|
85
|
-
login=True,
|
|
86
|
-
superuser=False,
|
|
87
|
-
inherit=False,
|
|
88
|
-
createdb=False,
|
|
89
|
-
createrole=False,
|
|
90
|
-
replication=False,
|
|
91
|
-
connection_limit=None,
|
|
92
|
-
# Details for speaking to PostgreSQL via `psql` CLI
|
|
93
|
-
psql_user=None,
|
|
94
|
-
psql_password=None,
|
|
95
|
-
psql_host=None,
|
|
96
|
-
psql_port=None,
|
|
97
|
-
):
|
|
98
|
-
"""
|
|
99
|
-
Add/remove PostgreSQL roles.
|
|
100
|
-
|
|
101
|
-
+ role: name of the role
|
|
102
|
-
+ present: whether the role should be present or absent
|
|
103
|
-
+ password: the password for the role
|
|
104
|
-
+ login: whether the role can login
|
|
105
|
-
+ superuser: whether role will be a superuser
|
|
106
|
-
+ inherit: whether the role inherits from other roles
|
|
107
|
-
+ createdb: whether the role is allowed to create databases
|
|
108
|
-
+ createrole: whether the role is allowed to create new roles
|
|
109
|
-
+ replication: whether this role is allowed to replicate
|
|
110
|
-
+ connection_limit: the connection limit for the role
|
|
111
|
-
+ psql_*: global module arguments, see above
|
|
112
|
-
|
|
113
|
-
Updates:
|
|
114
|
-
pyinfra will not attempt to change existing roles - it will either
|
|
115
|
-
create or drop roles, but not alter them (if the role exists this
|
|
116
|
-
operation will make no changes).
|
|
117
|
-
|
|
118
|
-
**Example:**
|
|
119
|
-
|
|
120
|
-
.. code:: python
|
|
121
|
-
|
|
122
|
-
postgresql.role(
|
|
123
|
-
name="Create the pyinfra PostgreSQL role",
|
|
124
|
-
role="pyinfra",
|
|
125
|
-
password="somepassword",
|
|
126
|
-
superuser=True,
|
|
127
|
-
login=True,
|
|
128
|
-
sudo_user="postgres",
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
"""
|
|
132
|
-
|
|
133
|
-
roles = host.get_fact(
|
|
134
|
-
PostgresqlRoles,
|
|
135
|
-
psql_user=psql_user,
|
|
136
|
-
psql_password=psql_password,
|
|
137
|
-
psql_host=psql_host,
|
|
138
|
-
psql_port=psql_port,
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
is_present = role in roles
|
|
142
|
-
|
|
143
|
-
# User not wanted?
|
|
144
|
-
if not present:
|
|
145
|
-
if is_present:
|
|
146
|
-
yield make_execute_psql_command(
|
|
147
|
-
'DROP ROLE "{0}"'.format(role),
|
|
148
|
-
user=psql_user,
|
|
149
|
-
password=psql_password,
|
|
150
|
-
host=psql_host,
|
|
151
|
-
port=psql_port,
|
|
152
|
-
)
|
|
153
|
-
roles.pop(role)
|
|
154
|
-
else:
|
|
155
|
-
host.noop("postgresql role {0} does not exist".format(role))
|
|
156
|
-
return
|
|
157
|
-
|
|
158
|
-
# If we want the user and they don't exist
|
|
159
|
-
if not is_present:
|
|
160
|
-
sql_bits = ['CREATE ROLE "{0}"'.format(role)]
|
|
161
|
-
|
|
162
|
-
for key, value in (
|
|
163
|
-
("LOGIN", login),
|
|
164
|
-
("SUPERUSER", superuser),
|
|
165
|
-
("INHERIT", inherit),
|
|
166
|
-
("CREATEDB", createdb),
|
|
167
|
-
("CREATEROLE", createrole),
|
|
168
|
-
("REPLICATION", replication),
|
|
169
|
-
):
|
|
170
|
-
if value:
|
|
171
|
-
sql_bits.append(key)
|
|
172
|
-
|
|
173
|
-
if connection_limit:
|
|
174
|
-
sql_bits.append("CONNECTION LIMIT {0}".format(connection_limit))
|
|
175
|
-
|
|
176
|
-
if password:
|
|
177
|
-
sql_bits.append(MaskString("PASSWORD '{0}'".format(password)))
|
|
178
|
-
|
|
179
|
-
yield make_execute_psql_command(
|
|
180
|
-
StringCommand(*sql_bits),
|
|
181
|
-
user=psql_user,
|
|
182
|
-
password=psql_password,
|
|
183
|
-
host=psql_host,
|
|
184
|
-
port=psql_port,
|
|
185
|
-
)
|
|
186
|
-
roles[role] = {
|
|
187
|
-
"super": superuser,
|
|
188
|
-
"createdb": createdb,
|
|
189
|
-
"createrole": createrole,
|
|
190
|
-
}
|
|
191
|
-
else:
|
|
192
|
-
host.noop("postgresql role {0} exists".format(role))
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
@operation
|
|
196
|
-
@_translate_legacy_args
|
|
197
|
-
def database(
|
|
198
|
-
database,
|
|
199
|
-
present=True,
|
|
200
|
-
owner=None,
|
|
201
|
-
template=None,
|
|
202
|
-
encoding=None,
|
|
203
|
-
lc_collate=None,
|
|
204
|
-
lc_ctype=None,
|
|
205
|
-
tablespace=None,
|
|
206
|
-
connection_limit=None,
|
|
207
|
-
# Details for speaking to PostgreSQL via `psql` CLI
|
|
208
|
-
psql_user=None,
|
|
209
|
-
psql_password=None,
|
|
210
|
-
psql_host=None,
|
|
211
|
-
psql_port=None,
|
|
212
|
-
):
|
|
213
|
-
"""
|
|
214
|
-
Add/remove PostgreSQL databases.
|
|
215
|
-
|
|
216
|
-
+ name: name of the database
|
|
217
|
-
+ present: whether the database should exist or not
|
|
218
|
-
+ owner: the PostgreSQL role that owns the database
|
|
219
|
-
+ template: name of the PostgreSQL template to use
|
|
220
|
-
+ encoding: encoding of the database
|
|
221
|
-
+ lc_collate: lc_collate of the database
|
|
222
|
-
+ lc_ctype: lc_ctype of the database
|
|
223
|
-
+ tablespace: the tablespace to use for the template
|
|
224
|
-
+ connection_limit: the connection limit to apply to the database
|
|
225
|
-
+ psql_*: global module arguments, see above
|
|
226
|
-
|
|
227
|
-
Updates:
|
|
228
|
-
pyinfra will not attempt to change existing databases - it will either
|
|
229
|
-
create or drop databases, but not alter them (if the db exists this
|
|
230
|
-
operation will make no changes).
|
|
231
|
-
|
|
232
|
-
**Example:**
|
|
233
|
-
|
|
234
|
-
.. code:: python
|
|
235
|
-
|
|
236
|
-
postgresql.database(
|
|
237
|
-
name="Create the pyinfra_stuff database",
|
|
238
|
-
database="pyinfra_stuff",
|
|
239
|
-
owner="pyinfra",
|
|
240
|
-
encoding="UTF8",
|
|
241
|
-
sudo_user="postgres",
|
|
242
|
-
)
|
|
243
|
-
|
|
244
|
-
"""
|
|
245
|
-
|
|
246
|
-
current_databases = host.get_fact(
|
|
247
|
-
PostgresqlDatabases,
|
|
248
|
-
psql_user=psql_user,
|
|
249
|
-
psql_password=psql_password,
|
|
250
|
-
psql_host=psql_host,
|
|
251
|
-
psql_port=psql_port,
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
is_present = database in current_databases
|
|
255
|
-
|
|
256
|
-
if not present:
|
|
257
|
-
if is_present:
|
|
258
|
-
yield make_execute_psql_command(
|
|
259
|
-
'DROP DATABASE "{0}"'.format(database),
|
|
260
|
-
user=psql_user,
|
|
261
|
-
password=psql_password,
|
|
262
|
-
host=psql_host,
|
|
263
|
-
port=psql_port,
|
|
264
|
-
)
|
|
265
|
-
current_databases.pop(database)
|
|
266
|
-
else:
|
|
267
|
-
host.noop("postgresql database {0} does not exist".format(database))
|
|
268
|
-
return
|
|
269
|
-
|
|
270
|
-
# We want the database but it doesn't exist
|
|
271
|
-
if present and not is_present:
|
|
272
|
-
sql_bits = ['CREATE DATABASE "{0}"'.format(database)]
|
|
273
|
-
|
|
274
|
-
for key, value in (
|
|
275
|
-
("OWNER", '"{0}"'.format(owner) if owner else owner),
|
|
276
|
-
("TEMPLATE", template),
|
|
277
|
-
("ENCODING", encoding),
|
|
278
|
-
("LC_COLLATE", lc_collate),
|
|
279
|
-
("LC_CTYPE", lc_ctype),
|
|
280
|
-
("TABLESPACE", tablespace),
|
|
281
|
-
("CONNECTION LIMIT", connection_limit),
|
|
282
|
-
):
|
|
283
|
-
if value:
|
|
284
|
-
sql_bits.append("{0} {1}".format(key, value))
|
|
285
|
-
|
|
286
|
-
yield make_execute_psql_command(
|
|
287
|
-
StringCommand(*sql_bits),
|
|
288
|
-
user=psql_user,
|
|
289
|
-
password=psql_password,
|
|
290
|
-
host=psql_host,
|
|
291
|
-
port=psql_port,
|
|
292
|
-
)
|
|
293
|
-
current_databases[database] = {
|
|
294
|
-
"template": template,
|
|
295
|
-
"encoding": encoding,
|
|
296
|
-
"lc_collate": lc_collate,
|
|
297
|
-
"lc_ctype": lc_ctype,
|
|
298
|
-
"tablespace": tablespace,
|
|
299
|
-
"connection_limit": connection_limit,
|
|
300
|
-
}
|
|
301
|
-
else:
|
|
302
|
-
host.noop("postgresql database {0} exists".format(database))
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
@operation(is_idempotent=False)
|
|
306
|
-
@_translate_legacy_args
|
|
307
|
-
def dump(
|
|
308
|
-
dest,
|
|
309
|
-
database=None,
|
|
310
|
-
# Details for speaking to PostgreSQL via `psql` CLI
|
|
311
|
-
psql_user=None,
|
|
312
|
-
psql_password=None,
|
|
313
|
-
psql_host=None,
|
|
314
|
-
psql_port=None,
|
|
315
|
-
):
|
|
316
|
-
"""
|
|
317
|
-
Dump a PostgreSQL database into a ``.sql`` file. Requires ``pg_dump``.
|
|
318
|
-
|
|
319
|
-
+ dest: name of the file to dump the SQL to
|
|
320
|
-
+ database: name of the database to dump
|
|
321
|
-
+ psql_*: global module arguments, see above
|
|
322
|
-
|
|
323
|
-
**Example:**
|
|
324
|
-
|
|
325
|
-
.. code:: python
|
|
326
|
-
|
|
327
|
-
postgresql.dump(
|
|
328
|
-
name="Dump the pyinfra_stuff database",
|
|
329
|
-
dest="/tmp/pyinfra_stuff.dump",
|
|
330
|
-
database="pyinfra_stuff",
|
|
331
|
-
sudo_user="postgres",
|
|
332
|
-
)
|
|
333
|
-
|
|
334
|
-
"""
|
|
335
|
-
|
|
336
|
-
yield StringCommand(
|
|
337
|
-
make_psql_command(
|
|
338
|
-
executable="pg_dump",
|
|
339
|
-
database=database,
|
|
340
|
-
user=psql_user,
|
|
341
|
-
password=psql_password,
|
|
342
|
-
host=psql_host,
|
|
343
|
-
port=psql_port,
|
|
344
|
-
),
|
|
345
|
-
">",
|
|
346
|
-
dest,
|
|
347
|
-
)
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
@operation(is_idempotent=False)
|
|
351
|
-
@_translate_legacy_args
|
|
352
|
-
def load(
|
|
353
|
-
src,
|
|
354
|
-
database=None,
|
|
355
|
-
# Details for speaking to PostgreSQL via `psql` CLI
|
|
356
|
-
psql_user=None,
|
|
357
|
-
psql_password=None,
|
|
358
|
-
psql_host=None,
|
|
359
|
-
psql_port=None,
|
|
360
|
-
):
|
|
361
|
-
"""
|
|
362
|
-
Load ``.sql`` file into a database.
|
|
363
|
-
|
|
364
|
-
+ src: the filename to read from
|
|
365
|
-
+ database: name of the database to import into
|
|
366
|
-
+ psql_*: global module arguments, see above
|
|
367
|
-
|
|
368
|
-
**Example:**
|
|
369
|
-
|
|
370
|
-
.. code:: python
|
|
371
|
-
|
|
372
|
-
postgresql.load(
|
|
373
|
-
name="Import the pyinfra_stuff dump into pyinfra_stuff_copy",
|
|
374
|
-
src="/tmp/pyinfra_stuff.dump",
|
|
375
|
-
database="pyinfra_stuff_copy",
|
|
376
|
-
sudo_user="postgres",
|
|
377
|
-
)
|
|
378
|
-
|
|
379
|
-
"""
|
|
380
|
-
|
|
381
|
-
yield StringCommand(
|
|
382
|
-
make_psql_command(
|
|
383
|
-
database=database,
|
|
384
|
-
user=psql_user,
|
|
385
|
-
password=psql_password,
|
|
386
|
-
host=psql_host,
|
|
387
|
-
port=psql_port,
|
|
388
|
-
),
|
|
389
|
-
"<",
|
|
390
|
-
src,
|
|
391
|
-
)
|
|
28
|
+
@operation(is_idempotent=False, is_deprecated=True)
|
|
29
|
+
def load(*args, **kwargs):
|
|
30
|
+
yield from postgres.load._inner(*args, **kwargs)
|
pyinfra/operations/puppet.py
CHANGED
pyinfra/operations/python.py
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
The Python module allows you to execute Python code within the context of a deploy.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Callable
|
|
6
8
|
|
|
7
|
-
from pyinfra import logger
|
|
8
9
|
from pyinfra.api import FunctionCommand, operation
|
|
9
|
-
from pyinfra.api.util import get_call_location
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
@operation(is_idempotent=False)
|
|
13
|
-
def call(function, *args, **kwargs):
|
|
12
|
+
@operation(is_idempotent=False, _set_in_op=False)
|
|
13
|
+
def call(function: Callable, *args, **kwargs):
|
|
14
14
|
"""
|
|
15
15
|
Execute a Python function within a deploy.
|
|
16
16
|
|
|
@@ -43,20 +43,11 @@ def call(function, *args, **kwargs):
|
|
|
43
43
|
|
|
44
44
|
"""
|
|
45
45
|
|
|
46
|
-
argspec = getfullargspec(function)
|
|
47
|
-
if "state" in argspec.args and "host" in argspec.args:
|
|
48
|
-
logger.warning(
|
|
49
|
-
"Callback functions used in `python.call` operations no "
|
|
50
|
-
f"longer take `state` and `host` arguments: {get_call_location(frame_offset=3)}",
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
kwargs.pop("state", None)
|
|
54
|
-
kwargs.pop("host", None)
|
|
55
46
|
yield FunctionCommand(function, args, kwargs)
|
|
56
47
|
|
|
57
48
|
|
|
58
|
-
@operation(is_idempotent=False)
|
|
59
|
-
def raise_exception(exception, *args, **kwargs):
|
|
49
|
+
@operation(is_idempotent=False, _set_in_op=False)
|
|
50
|
+
def raise_exception(exception: Exception, *args, **kwargs):
|
|
60
51
|
"""
|
|
61
52
|
Raise a Python exception within a deploy.
|
|
62
53
|
|
|
@@ -76,8 +67,6 @@ def raise_exception(exception, *args, **kwargs):
|
|
|
76
67
|
"""
|
|
77
68
|
|
|
78
69
|
def raise_exc(*args, **kwargs): # pragma: no cover
|
|
79
|
-
raise exception(*args, **kwargs)
|
|
70
|
+
raise exception(*args, **kwargs) # type: ignore[operator]
|
|
80
71
|
|
|
81
|
-
kwargs.pop("state", None)
|
|
82
|
-
kwargs.pop("host", None)
|
|
83
72
|
yield FunctionCommand(raise_exc, args, kwargs)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Manage runit services.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from pyinfra import host
|
|
8
|
+
from pyinfra.api import operation
|
|
9
|
+
from pyinfra.facts.files import File
|
|
10
|
+
from pyinfra.facts.runit import RunitManaged, RunitStatus
|
|
11
|
+
|
|
12
|
+
from .files import file, link
|
|
13
|
+
from .util.service import handle_service_control
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@operation()
|
|
17
|
+
def service(
|
|
18
|
+
service: str,
|
|
19
|
+
running: bool = True,
|
|
20
|
+
restarted: bool = False,
|
|
21
|
+
reloaded: bool = False,
|
|
22
|
+
command: Optional[str] = None,
|
|
23
|
+
enabled: Optional[bool] = None,
|
|
24
|
+
managed: bool = True,
|
|
25
|
+
svdir: str = "/var/service",
|
|
26
|
+
sourcedir: str = "/etc/sv",
|
|
27
|
+
):
|
|
28
|
+
"""
|
|
29
|
+
Manage the state of runit services.
|
|
30
|
+
|
|
31
|
+
+ service: name of the service to manage
|
|
32
|
+
+ running: whether the service should be running
|
|
33
|
+
+ restarted: whether the service should be restarted
|
|
34
|
+
+ reloaded: whether the service should be reloaded
|
|
35
|
+
+ command: custom command to pass like: ``sv <command> <service>``
|
|
36
|
+
+ enabled: whether this service should be enabled/disabled on boot
|
|
37
|
+
+ managed: whether runit should manage this service
|
|
38
|
+
|
|
39
|
+
For services to be controlled, they first need to be managed by runit by
|
|
40
|
+
adding a symlink to the service in ``SVDIR``.
|
|
41
|
+
By setting ``managed=False`` the symlink will be removed.
|
|
42
|
+
Other options won't have any effect after that.
|
|
43
|
+
Although the ``<service>/down`` file can still be controlled with the
|
|
44
|
+
``enabled`` option.
|
|
45
|
+
|
|
46
|
+
+ svdir: alternative ``SVDIR``
|
|
47
|
+
|
|
48
|
+
An alternative ``SVDIR`` can be specified. This can be used for user services.
|
|
49
|
+
|
|
50
|
+
+ sourcedir: where to search for available services
|
|
51
|
+
|
|
52
|
+
An alternative directory for available services can be specified.
|
|
53
|
+
Example: ``sourcedir=/etc/sv.local`` for services managed by the administrator.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
was_managed = service in host.get_fact(RunitManaged, service=service, svdir=svdir)
|
|
57
|
+
was_auto = not host.get_fact(File, path="{0}/{1}/down".format(sourcedir, service))
|
|
58
|
+
|
|
59
|
+
# Disable autostart for previously unmanaged services.
|
|
60
|
+
#
|
|
61
|
+
# Where ``running=False`` is requested, this prevents one case of briefly
|
|
62
|
+
# starting and stopping the service.
|
|
63
|
+
if not was_managed and managed and was_auto:
|
|
64
|
+
yield from auto._inner(
|
|
65
|
+
service=service,
|
|
66
|
+
auto=False,
|
|
67
|
+
sourcedir=sourcedir,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
yield from manage._inner(
|
|
71
|
+
service=service,
|
|
72
|
+
managed=managed,
|
|
73
|
+
svdir=svdir,
|
|
74
|
+
sourcedir=sourcedir,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Service wasn't managed before, so wait for ``runsv`` to start.
|
|
78
|
+
# ``runsvdir`` will check at least every 5 seconds for new services.
|
|
79
|
+
# Wait for at most 10 seconds for the service to be managed, otherwise fail.
|
|
80
|
+
if not was_managed and managed:
|
|
81
|
+
yield from wait_runsv._inner(
|
|
82
|
+
service=service,
|
|
83
|
+
svdir=svdir,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
if isinstance(enabled, bool):
|
|
87
|
+
yield from auto._inner(
|
|
88
|
+
service=service,
|
|
89
|
+
auto=enabled,
|
|
90
|
+
sourcedir=sourcedir,
|
|
91
|
+
)
|
|
92
|
+
else:
|
|
93
|
+
# restore previous state of ``<service>/down``
|
|
94
|
+
yield from auto._inner(
|
|
95
|
+
service=service,
|
|
96
|
+
auto=was_auto,
|
|
97
|
+
sourcedir=sourcedir,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Services need to be managed by ``runit`` for the other options to make sense.
|
|
101
|
+
if not managed:
|
|
102
|
+
return
|
|
103
|
+
|
|
104
|
+
yield from handle_service_control(
|
|
105
|
+
host,
|
|
106
|
+
service,
|
|
107
|
+
host.get_fact(RunitStatus, service=service, svdir=svdir),
|
|
108
|
+
"SVDIR={0} sv {{1}} {{0}}".format(svdir),
|
|
109
|
+
running,
|
|
110
|
+
restarted,
|
|
111
|
+
reloaded,
|
|
112
|
+
command,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@operation()
|
|
117
|
+
def manage(
|
|
118
|
+
service: str,
|
|
119
|
+
managed: bool = True,
|
|
120
|
+
svdir: str = "/var/service",
|
|
121
|
+
sourcedir: str = "/etc/sv",
|
|
122
|
+
):
|
|
123
|
+
"""
|
|
124
|
+
Manage runit svdir links.
|
|
125
|
+
|
|
126
|
+
+ service: name of the service to manage
|
|
127
|
+
+ managed: whether the link should exist
|
|
128
|
+
+ svdir: alternative ``SVDIR``
|
|
129
|
+
+ sourcedir: where to search for available services
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
yield from link._inner(
|
|
133
|
+
path="{0}/{1}".format(svdir, service),
|
|
134
|
+
target="{0}/{1}".format(sourcedir, service),
|
|
135
|
+
present=managed,
|
|
136
|
+
create_remote_dir=False,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@operation(is_idempotent=False)
|
|
141
|
+
def wait_runsv(
|
|
142
|
+
service: str,
|
|
143
|
+
svdir: str = "/var/service",
|
|
144
|
+
timeout: int = 10,
|
|
145
|
+
):
|
|
146
|
+
"""
|
|
147
|
+
Wait for runsv for ``service`` to be available.
|
|
148
|
+
|
|
149
|
+
+ service: name of the service to manage
|
|
150
|
+
+ svdir: alternative ``SVDIR``
|
|
151
|
+
+ timeout: time in seconds to wait
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
yield (
|
|
155
|
+
"export SVDIR={0}\n"
|
|
156
|
+
"for i in $(seq {1}); do\n"
|
|
157
|
+
" sv status {2} > /dev/null && exit 0\n"
|
|
158
|
+
" sleep 1;\n"
|
|
159
|
+
"done\n"
|
|
160
|
+
"exit 1"
|
|
161
|
+
).format(svdir, timeout, service)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@operation()
|
|
165
|
+
def auto(
|
|
166
|
+
service: str,
|
|
167
|
+
auto: bool = True,
|
|
168
|
+
sourcedir: str = "/etc/sv",
|
|
169
|
+
):
|
|
170
|
+
"""
|
|
171
|
+
Start service automatically by managing the ``service/down`` file.
|
|
172
|
+
|
|
173
|
+
+ service: name of the service to manage
|
|
174
|
+
+ auto: whether the service should start automatically
|
|
175
|
+
+ sourcedir: where to search for available services
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
yield from file._inner(
|
|
179
|
+
path="{0}/{1}/down".format(sourcedir, service),
|
|
180
|
+
present=not auto,
|
|
181
|
+
create_remote_dir=False,
|
|
182
|
+
)
|