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
pyinfra/operations/mysql.py
CHANGED
|
@@ -13,6 +13,8 @@ See the example/mysql.py
|
|
|
13
13
|
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
16
18
|
from pyinfra import host
|
|
17
19
|
from pyinfra.api import MaskString, OperationError, QuoteString, StringCommand, operation
|
|
18
20
|
from pyinfra.facts.mysql import (
|
|
@@ -26,13 +28,13 @@ from pyinfra.facts.mysql import (
|
|
|
26
28
|
|
|
27
29
|
@operation(is_idempotent=False)
|
|
28
30
|
def sql(
|
|
29
|
-
sql,
|
|
30
|
-
database=None,
|
|
31
|
+
sql: str,
|
|
32
|
+
database: str | None = None,
|
|
31
33
|
# Details for speaking to MySQL via `mysql` CLI
|
|
32
|
-
mysql_user=None,
|
|
33
|
-
mysql_password=None,
|
|
34
|
-
mysql_host=None,
|
|
35
|
-
mysql_port=None,
|
|
34
|
+
mysql_user: str | None = None,
|
|
35
|
+
mysql_password: str | None = None,
|
|
36
|
+
mysql_host: str | None = None,
|
|
37
|
+
mysql_port: int | None = None,
|
|
36
38
|
):
|
|
37
39
|
"""
|
|
38
40
|
Execute arbitrary SQL against MySQL.
|
|
@@ -54,27 +56,28 @@ def sql(
|
|
|
54
56
|
|
|
55
57
|
@operation()
|
|
56
58
|
def user(
|
|
57
|
-
user,
|
|
58
|
-
present=True,
|
|
59
|
-
user_hostname="localhost",
|
|
60
|
-
password=None,
|
|
61
|
-
privileges=None,
|
|
59
|
+
user: str,
|
|
60
|
+
present: bool = True,
|
|
61
|
+
user_hostname: str = "localhost",
|
|
62
|
+
password: str | None = None,
|
|
63
|
+
privileges: str | list[str] | None = None,
|
|
62
64
|
# MySQL REQUIRE SSL/TLS options
|
|
63
|
-
require=None, # SSL or X509
|
|
64
|
-
require_cipher=
|
|
65
|
-
require_issuer=
|
|
66
|
-
require_subject=
|
|
65
|
+
require: str | None = None, # SSL or X509
|
|
66
|
+
require_cipher: str | None = None,
|
|
67
|
+
require_issuer: str | None = None,
|
|
68
|
+
require_subject: str | None = None,
|
|
67
69
|
# MySQL WITH resource limit options
|
|
68
|
-
max_connections=None,
|
|
69
|
-
max_queries_per_hour=None,
|
|
70
|
-
max_updates_per_hour=None,
|
|
71
|
-
max_connections_per_hour=None,
|
|
70
|
+
max_connections: int | None = None,
|
|
71
|
+
max_queries_per_hour: int | None = None,
|
|
72
|
+
max_updates_per_hour: int | None = None,
|
|
73
|
+
max_connections_per_hour: int | None = None,
|
|
72
74
|
# Details for speaking to MySQL via `mysql` CLI via `mysql` CLI
|
|
73
|
-
mysql_user=None,
|
|
74
|
-
mysql_password=None,
|
|
75
|
-
mysql_host=None,
|
|
76
|
-
mysql_port=None,
|
|
75
|
+
mysql_user: str | None = None,
|
|
76
|
+
mysql_password: str | None = None,
|
|
77
|
+
mysql_host: str | None = None,
|
|
78
|
+
mysql_port: int | None = None,
|
|
77
79
|
):
|
|
80
|
+
...
|
|
78
81
|
"""
|
|
79
82
|
Add/remove/update MySQL users.
|
|
80
83
|
|
|
@@ -282,24 +285,25 @@ def user(
|
|
|
282
285
|
|
|
283
286
|
@operation()
|
|
284
287
|
def database(
|
|
285
|
-
database,
|
|
288
|
+
database: str,
|
|
286
289
|
# Desired database settings
|
|
287
|
-
present=True,
|
|
288
|
-
collate=None,
|
|
289
|
-
charset=None,
|
|
290
|
-
user=None,
|
|
291
|
-
user_hostname="localhost",
|
|
292
|
-
user_privileges="ALL",
|
|
290
|
+
present: bool = True,
|
|
291
|
+
collate: str | None = None,
|
|
292
|
+
charset: str | None = None,
|
|
293
|
+
user: str | None = None,
|
|
294
|
+
user_hostname: str = "localhost",
|
|
295
|
+
user_privileges: str | list[str] = "ALL",
|
|
293
296
|
# Details for speaking to MySQL via `mysql` CLI
|
|
294
|
-
mysql_user=None,
|
|
295
|
-
mysql_password=None,
|
|
296
|
-
mysql_host=None,
|
|
297
|
-
mysql_port=None,
|
|
297
|
+
mysql_user: str | None = None,
|
|
298
|
+
mysql_password: str | None = None,
|
|
299
|
+
mysql_host: str | None = None,
|
|
300
|
+
mysql_port: int | None = None,
|
|
298
301
|
):
|
|
302
|
+
...
|
|
299
303
|
"""
|
|
300
304
|
Add/remove MySQL databases.
|
|
301
305
|
|
|
302
|
-
+
|
|
306
|
+
+ database: the name of the database
|
|
303
307
|
+ present: whether the database should exist or not
|
|
304
308
|
+ collate: the collate to use when creating the database
|
|
305
309
|
+ charset: the charset to use when creating the database
|
|
@@ -384,18 +388,18 @@ def database(
|
|
|
384
388
|
|
|
385
389
|
@operation()
|
|
386
390
|
def privileges(
|
|
387
|
-
user,
|
|
388
|
-
privileges,
|
|
391
|
+
user: str,
|
|
392
|
+
privileges: str | list[str] | set[str],
|
|
389
393
|
user_hostname="localhost",
|
|
390
394
|
database="*",
|
|
391
395
|
table="*",
|
|
392
396
|
flush=True,
|
|
393
397
|
with_grant_option=False,
|
|
394
398
|
# Details for speaking to MySQL via `mysql` CLI
|
|
395
|
-
mysql_user=None,
|
|
396
|
-
mysql_password=None,
|
|
397
|
-
mysql_host=None,
|
|
398
|
-
mysql_port=None,
|
|
399
|
+
mysql_user: str | None = None,
|
|
400
|
+
mysql_password: str | None = None,
|
|
401
|
+
mysql_host: str | None = None,
|
|
402
|
+
mysql_port: int | None = None,
|
|
399
403
|
):
|
|
400
404
|
"""
|
|
401
405
|
Add/remove MySQL privileges for a user, either global, database or table specific.
|
|
@@ -524,13 +528,13 @@ _privileges = privileges # noqa: E305 (for use where kwarg is the same)
|
|
|
524
528
|
|
|
525
529
|
@operation(is_idempotent=False)
|
|
526
530
|
def dump(
|
|
527
|
-
dest,
|
|
528
|
-
database=None,
|
|
531
|
+
dest: str,
|
|
532
|
+
database: str | None = None,
|
|
529
533
|
# Details for speaking to MySQL via `mysql` CLI
|
|
530
|
-
mysql_user=None,
|
|
531
|
-
mysql_password=None,
|
|
532
|
-
mysql_host=None,
|
|
533
|
-
mysql_port=None,
|
|
534
|
+
mysql_user: str | None = None,
|
|
535
|
+
mysql_password: str | None = None,
|
|
536
|
+
mysql_host: str | None = None,
|
|
537
|
+
mysql_port: int | None = None,
|
|
534
538
|
):
|
|
535
539
|
"""
|
|
536
540
|
Dump a MySQL database into a ``.sql`` file. Requires ``mysqldump``.
|
|
@@ -565,13 +569,13 @@ def dump(
|
|
|
565
569
|
|
|
566
570
|
@operation(is_idempotent=False)
|
|
567
571
|
def load(
|
|
568
|
-
src,
|
|
569
|
-
database=None,
|
|
572
|
+
src: str,
|
|
573
|
+
database: str | None = None,
|
|
570
574
|
# Details for speaking to MySQL via `mysql` CLI
|
|
571
|
-
mysql_user=None,
|
|
572
|
-
mysql_password=None,
|
|
573
|
-
mysql_host=None,
|
|
574
|
-
mysql_port=None,
|
|
575
|
+
mysql_user: str | None = None,
|
|
576
|
+
mysql_password: str | None = None,
|
|
577
|
+
mysql_host: str | None = None,
|
|
578
|
+
mysql_port: int | None = None,
|
|
575
579
|
):
|
|
576
580
|
"""
|
|
577
581
|
Load ``.sql`` file into a database.
|
pyinfra/operations/npm.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Manage npm (aka node aka Node.js) 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.npm import NpmPackages
|
|
@@ -10,7 +12,12 @@ from .util.packaging import ensure_packages
|
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
@operation()
|
|
13
|
-
def packages(
|
|
15
|
+
def packages(
|
|
16
|
+
packages: str | list[str] | None = None,
|
|
17
|
+
present=True,
|
|
18
|
+
latest=False,
|
|
19
|
+
directory: str | None = None,
|
|
20
|
+
):
|
|
14
21
|
"""
|
|
15
22
|
Install/remove/update npm packages.
|
|
16
23
|
|
pyinfra/operations/openrc.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Manage OpenRC init services.
|
|
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.openrc import OpenrcEnabled, OpenrcStatus
|
|
@@ -11,12 +13,12 @@ from .util.service import handle_service_control
|
|
|
11
13
|
|
|
12
14
|
@operation()
|
|
13
15
|
def service(
|
|
14
|
-
service,
|
|
16
|
+
service: str,
|
|
15
17
|
running=True,
|
|
16
18
|
restarted=False,
|
|
17
19
|
reloaded=False,
|
|
18
|
-
command=None,
|
|
19
|
-
enabled=None,
|
|
20
|
+
command: str | None = None,
|
|
21
|
+
enabled: bool | None = None,
|
|
20
22
|
runlevel="default",
|
|
21
23
|
):
|
|
22
24
|
"""
|
pyinfra/operations/pacman.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Manage pacman packages. (Arch Linux package manager)
|
|
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.pacman import PacmanPackages, PacmanUnpackGroup
|
|
@@ -35,7 +37,7 @@ _update = update._inner # noqa: E305
|
|
|
35
37
|
|
|
36
38
|
@operation()
|
|
37
39
|
def packages(
|
|
38
|
-
packages=None,
|
|
40
|
+
packages: str | list[str] | None = None,
|
|
39
41
|
present=True,
|
|
40
42
|
update=False,
|
|
41
43
|
upgrade=False,
|
|
@@ -75,8 +77,5 @@ def packages(
|
|
|
75
77
|
present,
|
|
76
78
|
install_command="pacman --noconfirm -S",
|
|
77
79
|
uninstall_command="pacman --noconfirm -R",
|
|
78
|
-
expand_package_fact=lambda package: host.get_fact(
|
|
79
|
-
PacmanUnpackGroup,
|
|
80
|
-
name=package,
|
|
81
|
-
),
|
|
80
|
+
expand_package_fact=lambda package: host.get_fact(PacmanUnpackGroup, package=package),
|
|
82
81
|
)
|
pyinfra/operations/pip.py
CHANGED
|
@@ -3,6 +3,8 @@ Manage pip (python) packages. Compatible globally or inside
|
|
|
3
3
|
a virtualenv (virtual environment).
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
6
8
|
from pyinfra import host
|
|
7
9
|
from pyinfra.api import operation
|
|
8
10
|
from pyinfra.facts.files import File
|
|
@@ -14,8 +16,8 @@ from .util.packaging import ensure_packages
|
|
|
14
16
|
|
|
15
17
|
@operation()
|
|
16
18
|
def virtualenv(
|
|
17
|
-
path,
|
|
18
|
-
python=None,
|
|
19
|
+
path: str,
|
|
20
|
+
python: str | None = None,
|
|
19
21
|
venv=False,
|
|
20
22
|
site_packages=False,
|
|
21
23
|
always_copy=False,
|
|
@@ -81,8 +83,8 @@ _virtualenv = virtualenv._inner # noqa
|
|
|
81
83
|
|
|
82
84
|
@operation()
|
|
83
85
|
def venv(
|
|
84
|
-
path,
|
|
85
|
-
python=None,
|
|
86
|
+
path: str,
|
|
87
|
+
python: str | None = None,
|
|
86
88
|
site_packages=False,
|
|
87
89
|
always_copy=False,
|
|
88
90
|
present=True,
|
|
@@ -117,14 +119,14 @@ def venv(
|
|
|
117
119
|
|
|
118
120
|
@operation()
|
|
119
121
|
def packages(
|
|
120
|
-
packages=None,
|
|
122
|
+
packages: str | list[str] | None = None,
|
|
121
123
|
present=True,
|
|
122
124
|
latest=False,
|
|
123
|
-
requirements=None,
|
|
125
|
+
requirements: str | None = None,
|
|
124
126
|
pip="pip",
|
|
125
|
-
virtualenv=None,
|
|
126
|
-
virtualenv_kwargs=None,
|
|
127
|
-
extra_install_args=None,
|
|
127
|
+
virtualenv: str | None = None,
|
|
128
|
+
virtualenv_kwargs: dict | None = None,
|
|
129
|
+
extra_install_args: str | None = None,
|
|
128
130
|
):
|
|
129
131
|
"""
|
|
130
132
|
Install/remove/update pip packages.
|
|
@@ -185,6 +187,11 @@ def packages(
|
|
|
185
187
|
if packages:
|
|
186
188
|
current_packages = host.get_fact(PipPackages, pip=pip)
|
|
187
189
|
|
|
190
|
+
# PEP-0426 states that Python packages should be compared using lowercase, so lowercase both
|
|
191
|
+
# the input packages and the fact packages before comparison.
|
|
192
|
+
packages = [pkg.lower() for pkg in packages]
|
|
193
|
+
current_packages = {pkg.lower(): versions for pkg, versions in current_packages.items()}
|
|
194
|
+
|
|
188
195
|
yield from ensure_packages(
|
|
189
196
|
host,
|
|
190
197
|
packages,
|
pyinfra/operations/pkg.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Manage BSD packages and repositories. Note that BSD package names are case-sensitive.
|
|
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.files import File
|
|
@@ -12,7 +14,7 @@ from .util.packaging import ensure_packages
|
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
@operation()
|
|
15
|
-
def packages(packages=None, present=True, pkg_path=None):
|
|
17
|
+
def packages(packages: str | list[str] | None = None, present=True, pkg_path: str | None = None):
|
|
16
18
|
"""
|
|
17
19
|
Install/remove/update pkg packages. This will use ``pkg ...`` where available
|
|
18
20
|
(FreeBSD) and the ``pkg_*`` variants elsewhere.
|
pyinfra/operations/pkgin.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Manage pkgin 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.pkgin import PkginPackages
|
|
@@ -35,7 +37,7 @@ _update = update._inner # noqa: E305
|
|
|
35
37
|
|
|
36
38
|
@operation()
|
|
37
39
|
def packages(
|
|
38
|
-
packages=None,
|
|
40
|
+
packages: str | list[str] | None = None,
|
|
39
41
|
present=True,
|
|
40
42
|
latest=False,
|
|
41
43
|
update=False,
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The PostgreSQL modules manage PostgreSQL databases, users and privileges.
|
|
3
|
+
|
|
4
|
+
Requires the ``psql`` CLI executable on the target host(s).
|
|
5
|
+
|
|
6
|
+
All operations in this module take four optional arguments:
|
|
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
|
|
11
|
+
|
|
12
|
+
See example/postgresql.py for detailed example
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from pyinfra import host
|
|
19
|
+
from pyinfra.api import MaskString, StringCommand, operation
|
|
20
|
+
from pyinfra.facts.postgres import (
|
|
21
|
+
PostgresDatabases,
|
|
22
|
+
PostgresRoles,
|
|
23
|
+
make_execute_psql_command,
|
|
24
|
+
make_psql_command,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@operation(is_idempotent=False)
|
|
29
|
+
def sql(
|
|
30
|
+
sql: str,
|
|
31
|
+
database: str | None = None,
|
|
32
|
+
# Details for speaking to PostgreSQL via `psql` CLI
|
|
33
|
+
psql_user: str | None = None,
|
|
34
|
+
psql_password: str | None = None,
|
|
35
|
+
psql_host: str | None = None,
|
|
36
|
+
psql_port: int | None = None,
|
|
37
|
+
):
|
|
38
|
+
"""
|
|
39
|
+
Execute arbitrary SQL against PostgreSQL.
|
|
40
|
+
|
|
41
|
+
+ sql: SQL command(s) to execute
|
|
42
|
+
+ database: optional database to execute against
|
|
43
|
+
+ psql_*: global module arguments, see above
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
yield make_execute_psql_command(
|
|
47
|
+
sql,
|
|
48
|
+
database=database,
|
|
49
|
+
user=psql_user,
|
|
50
|
+
password=psql_password,
|
|
51
|
+
host=psql_host,
|
|
52
|
+
port=psql_port,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@operation()
|
|
57
|
+
def role(
|
|
58
|
+
role: str,
|
|
59
|
+
present=True,
|
|
60
|
+
password: str | None = None,
|
|
61
|
+
login=True,
|
|
62
|
+
superuser=False,
|
|
63
|
+
inherit=False,
|
|
64
|
+
createdb=False,
|
|
65
|
+
createrole=False,
|
|
66
|
+
replication=False,
|
|
67
|
+
connection_limit: int | None = None,
|
|
68
|
+
# Details for speaking to PostgreSQL via `psql` CLI
|
|
69
|
+
psql_user: str | None = None,
|
|
70
|
+
psql_password: str | None = None,
|
|
71
|
+
psql_host: str | None = None,
|
|
72
|
+
psql_port: int | None = None,
|
|
73
|
+
):
|
|
74
|
+
"""
|
|
75
|
+
Add/remove PostgreSQL roles.
|
|
76
|
+
|
|
77
|
+
+ role: name of the role
|
|
78
|
+
+ present: whether the role should be present or absent
|
|
79
|
+
+ password: the password for the role
|
|
80
|
+
+ login: whether the role can login
|
|
81
|
+
+ superuser: whether role will be a superuser
|
|
82
|
+
+ inherit: whether the role inherits from other roles
|
|
83
|
+
+ createdb: whether the role is allowed to create databases
|
|
84
|
+
+ createrole: whether the role is allowed to create new roles
|
|
85
|
+
+ replication: whether this role is allowed to replicate
|
|
86
|
+
+ connection_limit: the connection limit for the role
|
|
87
|
+
+ psql_*: global module arguments, see above
|
|
88
|
+
|
|
89
|
+
Updates:
|
|
90
|
+
pyinfra will not attempt to change existing roles - it will either
|
|
91
|
+
create or drop roles, but not alter them (if the role exists this
|
|
92
|
+
operation will make no changes).
|
|
93
|
+
|
|
94
|
+
**Example:**
|
|
95
|
+
|
|
96
|
+
.. code:: python
|
|
97
|
+
|
|
98
|
+
postgresql.role(
|
|
99
|
+
name="Create the pyinfra PostgreSQL role",
|
|
100
|
+
role="pyinfra",
|
|
101
|
+
password="somepassword",
|
|
102
|
+
superuser=True,
|
|
103
|
+
login=True,
|
|
104
|
+
sudo_user="postgres",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
roles = host.get_fact(
|
|
110
|
+
PostgresRoles,
|
|
111
|
+
psql_user=psql_user,
|
|
112
|
+
psql_password=psql_password,
|
|
113
|
+
psql_host=psql_host,
|
|
114
|
+
psql_port=psql_port,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
is_present = role in roles
|
|
118
|
+
|
|
119
|
+
# User not wanted?
|
|
120
|
+
if not present:
|
|
121
|
+
if is_present:
|
|
122
|
+
yield make_execute_psql_command(
|
|
123
|
+
'DROP ROLE "{0}"'.format(role),
|
|
124
|
+
user=psql_user,
|
|
125
|
+
password=psql_password,
|
|
126
|
+
host=psql_host,
|
|
127
|
+
port=psql_port,
|
|
128
|
+
)
|
|
129
|
+
else:
|
|
130
|
+
host.noop("postgresql role {0} does not exist".format(role))
|
|
131
|
+
return
|
|
132
|
+
|
|
133
|
+
# If we want the user and they don't exist
|
|
134
|
+
if not is_present:
|
|
135
|
+
sql_bits = ['CREATE ROLE "{0}"'.format(role)]
|
|
136
|
+
|
|
137
|
+
for key, value in (
|
|
138
|
+
("LOGIN", login),
|
|
139
|
+
("SUPERUSER", superuser),
|
|
140
|
+
("INHERIT", inherit),
|
|
141
|
+
("CREATEDB", createdb),
|
|
142
|
+
("CREATEROLE", createrole),
|
|
143
|
+
("REPLICATION", replication),
|
|
144
|
+
):
|
|
145
|
+
if value:
|
|
146
|
+
sql_bits.append(key)
|
|
147
|
+
|
|
148
|
+
if connection_limit:
|
|
149
|
+
sql_bits.append("CONNECTION LIMIT {0}".format(connection_limit))
|
|
150
|
+
|
|
151
|
+
if password:
|
|
152
|
+
sql_bits.append(MaskString("PASSWORD '{0}'".format(password)))
|
|
153
|
+
|
|
154
|
+
yield make_execute_psql_command(
|
|
155
|
+
StringCommand(*sql_bits),
|
|
156
|
+
user=psql_user,
|
|
157
|
+
password=psql_password,
|
|
158
|
+
host=psql_host,
|
|
159
|
+
port=psql_port,
|
|
160
|
+
)
|
|
161
|
+
else:
|
|
162
|
+
host.noop("postgresql role {0} exists".format(role))
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@operation()
|
|
166
|
+
def database(
|
|
167
|
+
database: str,
|
|
168
|
+
present=True,
|
|
169
|
+
owner: str | None = None,
|
|
170
|
+
template: str | None = None,
|
|
171
|
+
encoding: str | None = None,
|
|
172
|
+
lc_collate: str | None = None,
|
|
173
|
+
lc_ctype: str | None = None,
|
|
174
|
+
tablespace: str | None = None,
|
|
175
|
+
connection_limit: int | None = None,
|
|
176
|
+
# Details for speaking to PostgreSQL via `psql` CLI
|
|
177
|
+
psql_user: str | None = None,
|
|
178
|
+
psql_password: str | None = None,
|
|
179
|
+
psql_host: str | None = None,
|
|
180
|
+
psql_port: int | None = None,
|
|
181
|
+
):
|
|
182
|
+
"""
|
|
183
|
+
Add/remove PostgreSQL databases.
|
|
184
|
+
|
|
185
|
+
+ name: name of the database
|
|
186
|
+
+ present: whether the database should exist or not
|
|
187
|
+
+ owner: the PostgreSQL role that owns the database
|
|
188
|
+
+ template: name of the PostgreSQL template to use
|
|
189
|
+
+ encoding: encoding of the database
|
|
190
|
+
+ lc_collate: lc_collate of the database
|
|
191
|
+
+ lc_ctype: lc_ctype of the database
|
|
192
|
+
+ tablespace: the tablespace to use for the template
|
|
193
|
+
+ connection_limit: the connection limit to apply to the database
|
|
194
|
+
+ psql_*: global module arguments, see above
|
|
195
|
+
|
|
196
|
+
Updates:
|
|
197
|
+
pyinfra will not attempt to change existing databases - it will either
|
|
198
|
+
create or drop databases, but not alter them (if the db exists this
|
|
199
|
+
operation will make no changes).
|
|
200
|
+
|
|
201
|
+
**Example:**
|
|
202
|
+
|
|
203
|
+
.. code:: python
|
|
204
|
+
|
|
205
|
+
postgresql.database(
|
|
206
|
+
name="Create the pyinfra_stuff database",
|
|
207
|
+
database="pyinfra_stuff",
|
|
208
|
+
owner="pyinfra",
|
|
209
|
+
encoding="UTF8",
|
|
210
|
+
sudo_user="postgres",
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
current_databases = host.get_fact(
|
|
216
|
+
PostgresDatabases,
|
|
217
|
+
psql_user=psql_user,
|
|
218
|
+
psql_password=psql_password,
|
|
219
|
+
psql_host=psql_host,
|
|
220
|
+
psql_port=psql_port,
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
is_present = database in current_databases
|
|
224
|
+
|
|
225
|
+
if not present:
|
|
226
|
+
if is_present:
|
|
227
|
+
yield make_execute_psql_command(
|
|
228
|
+
'DROP DATABASE "{0}"'.format(database),
|
|
229
|
+
user=psql_user,
|
|
230
|
+
password=psql_password,
|
|
231
|
+
host=psql_host,
|
|
232
|
+
port=psql_port,
|
|
233
|
+
)
|
|
234
|
+
else:
|
|
235
|
+
host.noop("postgresql database {0} does not exist".format(database))
|
|
236
|
+
return
|
|
237
|
+
|
|
238
|
+
# We want the database but it doesn't exist
|
|
239
|
+
if present and not is_present:
|
|
240
|
+
sql_bits = ['CREATE DATABASE "{0}"'.format(database)]
|
|
241
|
+
|
|
242
|
+
for key, value in (
|
|
243
|
+
("OWNER", '"{0}"'.format(owner) if owner else owner),
|
|
244
|
+
("TEMPLATE", template),
|
|
245
|
+
("ENCODING", encoding),
|
|
246
|
+
("LC_COLLATE", lc_collate),
|
|
247
|
+
("LC_CTYPE", lc_ctype),
|
|
248
|
+
("TABLESPACE", tablespace),
|
|
249
|
+
("CONNECTION LIMIT", connection_limit),
|
|
250
|
+
):
|
|
251
|
+
if value:
|
|
252
|
+
sql_bits.append("{0} {1}".format(key, value))
|
|
253
|
+
|
|
254
|
+
yield make_execute_psql_command(
|
|
255
|
+
StringCommand(*sql_bits),
|
|
256
|
+
user=psql_user,
|
|
257
|
+
password=psql_password,
|
|
258
|
+
host=psql_host,
|
|
259
|
+
port=psql_port,
|
|
260
|
+
)
|
|
261
|
+
else:
|
|
262
|
+
host.noop("postgresql database {0} exists".format(database))
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
@operation(is_idempotent=False)
|
|
266
|
+
def dump(
|
|
267
|
+
dest: str,
|
|
268
|
+
database: str | None = None,
|
|
269
|
+
# Details for speaking to PostgreSQL via `psql` CLI
|
|
270
|
+
psql_user: str | None = None,
|
|
271
|
+
psql_password: str | None = None,
|
|
272
|
+
psql_host: str | None = None,
|
|
273
|
+
psql_port: int | None = None,
|
|
274
|
+
):
|
|
275
|
+
"""
|
|
276
|
+
Dump a PostgreSQL database into a ``.sql`` file. Requires ``pg_dump``.
|
|
277
|
+
|
|
278
|
+
+ dest: name of the file to dump the SQL to
|
|
279
|
+
+ database: name of the database to dump
|
|
280
|
+
+ psql_*: global module arguments, see above
|
|
281
|
+
|
|
282
|
+
**Example:**
|
|
283
|
+
|
|
284
|
+
.. code:: python
|
|
285
|
+
|
|
286
|
+
postgresql.dump(
|
|
287
|
+
name="Dump the pyinfra_stuff database",
|
|
288
|
+
dest="/tmp/pyinfra_stuff.dump",
|
|
289
|
+
database="pyinfra_stuff",
|
|
290
|
+
sudo_user="postgres",
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
"""
|
|
294
|
+
|
|
295
|
+
yield StringCommand(
|
|
296
|
+
make_psql_command(
|
|
297
|
+
executable="pg_dump",
|
|
298
|
+
database=database,
|
|
299
|
+
user=psql_user,
|
|
300
|
+
password=psql_password,
|
|
301
|
+
host=psql_host,
|
|
302
|
+
port=psql_port,
|
|
303
|
+
),
|
|
304
|
+
">",
|
|
305
|
+
dest,
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
@operation(is_idempotent=False)
|
|
310
|
+
def load(
|
|
311
|
+
src: str,
|
|
312
|
+
database: str | None = None,
|
|
313
|
+
# Details for speaking to PostgreSQL via `psql` CLI
|
|
314
|
+
psql_user: str | None = None,
|
|
315
|
+
psql_password: str | None = None,
|
|
316
|
+
psql_host: str | None = None,
|
|
317
|
+
psql_port: int | None = None,
|
|
318
|
+
):
|
|
319
|
+
"""
|
|
320
|
+
Load ``.sql`` file into a database.
|
|
321
|
+
|
|
322
|
+
+ src: the filename to read from
|
|
323
|
+
+ database: name of the database to import into
|
|
324
|
+
+ psql_*: global module arguments, see above
|
|
325
|
+
|
|
326
|
+
**Example:**
|
|
327
|
+
|
|
328
|
+
.. code:: python
|
|
329
|
+
|
|
330
|
+
postgresql.load(
|
|
331
|
+
name="Import the pyinfra_stuff dump into pyinfra_stuff_copy",
|
|
332
|
+
src="/tmp/pyinfra_stuff.dump",
|
|
333
|
+
database="pyinfra_stuff_copy",
|
|
334
|
+
sudo_user="postgres",
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
"""
|
|
338
|
+
|
|
339
|
+
yield StringCommand(
|
|
340
|
+
make_psql_command(
|
|
341
|
+
database=database,
|
|
342
|
+
user=psql_user,
|
|
343
|
+
password=psql_password,
|
|
344
|
+
host=psql_host,
|
|
345
|
+
port=psql_port,
|
|
346
|
+
),
|
|
347
|
+
"<",
|
|
348
|
+
src,
|
|
349
|
+
)
|