pyinfra 0.11.dev3__py3-none-any.whl → 3.6__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/__init__.py +9 -12
- pyinfra/__main__.py +4 -0
- pyinfra/api/__init__.py +19 -3
- pyinfra/api/arguments.py +413 -0
- pyinfra/api/arguments_typed.py +79 -0
- pyinfra/api/command.py +274 -0
- pyinfra/api/config.py +222 -28
- pyinfra/api/connect.py +33 -13
- pyinfra/api/connectors.py +27 -0
- pyinfra/api/deploy.py +65 -66
- pyinfra/api/exceptions.py +73 -18
- pyinfra/api/facts.py +267 -200
- pyinfra/api/host.py +416 -50
- pyinfra/api/inventory.py +121 -160
- pyinfra/api/metadata.py +69 -0
- pyinfra/api/operation.py +432 -262
- pyinfra/api/operations.py +273 -260
- pyinfra/api/state.py +302 -248
- pyinfra/api/util.py +309 -369
- pyinfra/connectors/base.py +173 -0
- pyinfra/connectors/chroot.py +212 -0
- pyinfra/connectors/docker.py +405 -0
- pyinfra/connectors/dockerssh.py +297 -0
- pyinfra/connectors/local.py +238 -0
- pyinfra/connectors/scp/__init__.py +1 -0
- pyinfra/connectors/scp/client.py +204 -0
- pyinfra/connectors/ssh.py +727 -0
- pyinfra/connectors/ssh_util.py +114 -0
- pyinfra/connectors/sshuserclient/client.py +309 -0
- pyinfra/connectors/sshuserclient/config.py +102 -0
- pyinfra/connectors/terraform.py +135 -0
- pyinfra/connectors/util.py +417 -0
- pyinfra/connectors/vagrant.py +183 -0
- pyinfra/context.py +145 -0
- pyinfra/facts/__init__.py +7 -6
- pyinfra/facts/apk.py +22 -7
- pyinfra/facts/apt.py +117 -60
- pyinfra/facts/brew.py +100 -15
- pyinfra/facts/bsdinit.py +23 -0
- pyinfra/facts/cargo.py +37 -0
- pyinfra/facts/choco.py +47 -0
- pyinfra/facts/crontab.py +195 -0
- pyinfra/facts/deb.py +94 -0
- pyinfra/facts/dnf.py +48 -0
- pyinfra/facts/docker.py +96 -23
- pyinfra/facts/efibootmgr.py +113 -0
- pyinfra/facts/files.py +629 -58
- pyinfra/facts/flatpak.py +77 -0
- pyinfra/facts/freebsd.py +70 -0
- pyinfra/facts/gem.py +19 -6
- pyinfra/facts/git.py +59 -14
- pyinfra/facts/gpg.py +150 -0
- pyinfra/facts/hardware.py +313 -167
- pyinfra/facts/iptables.py +72 -62
- pyinfra/facts/launchd.py +44 -0
- pyinfra/facts/lxd.py +17 -4
- pyinfra/facts/mysql.py +122 -86
- pyinfra/facts/npm.py +17 -9
- pyinfra/facts/openrc.py +71 -0
- pyinfra/facts/opkg.py +246 -0
- pyinfra/facts/pacman.py +50 -7
- pyinfra/facts/pip.py +24 -7
- pyinfra/facts/pipx.py +82 -0
- pyinfra/facts/pkg.py +15 -6
- pyinfra/facts/pkgin.py +35 -0
- pyinfra/facts/podman.py +54 -0
- pyinfra/facts/postgres.py +178 -0
- pyinfra/facts/postgresql.py +6 -147
- pyinfra/facts/rpm.py +105 -0
- pyinfra/facts/runit.py +77 -0
- pyinfra/facts/selinux.py +161 -0
- pyinfra/facts/server.py +762 -285
- pyinfra/facts/snap.py +88 -0
- pyinfra/facts/systemd.py +139 -0
- pyinfra/facts/sysvinit.py +59 -0
- pyinfra/facts/upstart.py +35 -0
- pyinfra/facts/util/__init__.py +17 -0
- pyinfra/facts/util/databases.py +4 -6
- pyinfra/facts/util/packaging.py +37 -6
- pyinfra/facts/util/units.py +30 -0
- pyinfra/facts/util/win_files.py +99 -0
- pyinfra/facts/vzctl.py +20 -13
- pyinfra/facts/xbps.py +35 -0
- pyinfra/facts/yum.py +34 -40
- pyinfra/facts/zfs.py +77 -0
- pyinfra/facts/zypper.py +42 -0
- pyinfra/local.py +45 -83
- pyinfra/operations/__init__.py +12 -0
- pyinfra/operations/apk.py +99 -0
- pyinfra/operations/apt.py +496 -0
- pyinfra/operations/brew.py +232 -0
- pyinfra/operations/bsdinit.py +59 -0
- pyinfra/operations/cargo.py +45 -0
- pyinfra/operations/choco.py +61 -0
- pyinfra/operations/crontab.py +194 -0
- pyinfra/operations/dnf.py +213 -0
- pyinfra/operations/docker.py +492 -0
- pyinfra/operations/files.py +2014 -0
- pyinfra/operations/flatpak.py +95 -0
- pyinfra/operations/freebsd/__init__.py +12 -0
- pyinfra/operations/freebsd/freebsd_update.py +70 -0
- pyinfra/operations/freebsd/pkg.py +219 -0
- pyinfra/operations/freebsd/service.py +116 -0
- pyinfra/operations/freebsd/sysrc.py +92 -0
- pyinfra/operations/gem.py +48 -0
- pyinfra/operations/git.py +420 -0
- pyinfra/operations/iptables.py +312 -0
- pyinfra/operations/launchd.py +45 -0
- pyinfra/operations/lxd.py +69 -0
- pyinfra/operations/mysql.py +610 -0
- pyinfra/operations/npm.py +57 -0
- pyinfra/operations/openrc.py +63 -0
- pyinfra/operations/opkg.py +89 -0
- pyinfra/operations/pacman.py +82 -0
- pyinfra/operations/pip.py +206 -0
- pyinfra/operations/pipx.py +103 -0
- pyinfra/operations/pkg.py +71 -0
- pyinfra/operations/pkgin.py +92 -0
- pyinfra/operations/postgres.py +437 -0
- pyinfra/operations/postgresql.py +30 -0
- pyinfra/operations/puppet.py +41 -0
- pyinfra/operations/python.py +73 -0
- pyinfra/operations/runit.py +184 -0
- pyinfra/operations/selinux.py +190 -0
- pyinfra/operations/server.py +1100 -0
- pyinfra/operations/snap.py +118 -0
- pyinfra/operations/ssh.py +217 -0
- pyinfra/operations/systemd.py +150 -0
- pyinfra/operations/sysvinit.py +142 -0
- pyinfra/operations/upstart.py +68 -0
- pyinfra/operations/util/__init__.py +12 -0
- pyinfra/operations/util/docker.py +407 -0
- pyinfra/operations/util/files.py +247 -0
- pyinfra/operations/util/packaging.py +338 -0
- pyinfra/operations/util/service.py +46 -0
- pyinfra/operations/vzctl.py +137 -0
- pyinfra/operations/xbps.py +78 -0
- pyinfra/operations/yum.py +213 -0
- pyinfra/operations/zfs.py +176 -0
- pyinfra/operations/zypper.py +193 -0
- pyinfra/progress.py +44 -32
- pyinfra/py.typed +0 -0
- pyinfra/version.py +9 -1
- pyinfra-3.6.dist-info/METADATA +142 -0
- pyinfra-3.6.dist-info/RECORD +160 -0
- {pyinfra-0.11.dev3.dist-info → pyinfra-3.6.dist-info}/WHEEL +1 -2
- pyinfra-3.6.dist-info/entry_points.txt +12 -0
- {pyinfra-0.11.dev3.dist-info → pyinfra-3.6.dist-info/licenses}/LICENSE.md +1 -1
- pyinfra_cli/__init__.py +1 -0
- pyinfra_cli/cli.py +793 -0
- pyinfra_cli/commands.py +66 -0
- pyinfra_cli/exceptions.py +155 -65
- pyinfra_cli/inventory.py +233 -89
- pyinfra_cli/log.py +39 -43
- pyinfra_cli/main.py +26 -495
- pyinfra_cli/prints.py +215 -156
- pyinfra_cli/util.py +172 -105
- pyinfra_cli/virtualenv.py +25 -20
- pyinfra/api/connectors/__init__.py +0 -21
- pyinfra/api/connectors/ansible.py +0 -99
- pyinfra/api/connectors/docker.py +0 -178
- pyinfra/api/connectors/local.py +0 -169
- pyinfra/api/connectors/ssh.py +0 -402
- pyinfra/api/connectors/sshuserclient/client.py +0 -105
- pyinfra/api/connectors/sshuserclient/config.py +0 -90
- pyinfra/api/connectors/util.py +0 -63
- pyinfra/api/connectors/vagrant.py +0 -155
- pyinfra/facts/init.py +0 -176
- pyinfra/facts/util/files.py +0 -102
- pyinfra/hook.py +0 -41
- pyinfra/modules/__init__.py +0 -11
- pyinfra/modules/apk.py +0 -64
- pyinfra/modules/apt.py +0 -272
- pyinfra/modules/brew.py +0 -122
- pyinfra/modules/files.py +0 -711
- pyinfra/modules/gem.py +0 -30
- pyinfra/modules/git.py +0 -115
- pyinfra/modules/init.py +0 -344
- pyinfra/modules/iptables.py +0 -271
- pyinfra/modules/lxd.py +0 -45
- pyinfra/modules/mysql.py +0 -347
- pyinfra/modules/npm.py +0 -47
- pyinfra/modules/pacman.py +0 -60
- pyinfra/modules/pip.py +0 -99
- pyinfra/modules/pkg.py +0 -43
- pyinfra/modules/postgresql.py +0 -245
- pyinfra/modules/puppet.py +0 -20
- pyinfra/modules/python.py +0 -37
- pyinfra/modules/server.py +0 -524
- pyinfra/modules/ssh.py +0 -150
- pyinfra/modules/util/files.py +0 -52
- pyinfra/modules/util/packaging.py +0 -118
- pyinfra/modules/vzctl.py +0 -133
- pyinfra/modules/yum.py +0 -171
- pyinfra/pseudo_modules.py +0 -64
- pyinfra-0.11.dev3.dist-info/.DS_Store +0 -0
- pyinfra-0.11.dev3.dist-info/METADATA +0 -135
- pyinfra-0.11.dev3.dist-info/RECORD +0 -95
- pyinfra-0.11.dev3.dist-info/entry_points.txt +0 -3
- pyinfra-0.11.dev3.dist-info/top_level.txt +0 -2
- pyinfra_cli/__main__.py +0 -40
- pyinfra_cli/config.py +0 -92
- /pyinfra/{modules/util → connectors}/__init__.py +0 -0
- /pyinfra/{api/connectors → connectors}/sshuserclient/__init__.py +0 -0
|
@@ -0,0 +1,437 @@
|
|
|
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
|
+
+ ``psql_database``: the database on the server to connect to
|
|
12
|
+
|
|
13
|
+
See example/postgresql.py for detailed example
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from pyinfra import host
|
|
20
|
+
from pyinfra.api import MaskString, QuoteString, StringCommand, operation
|
|
21
|
+
from pyinfra.facts.postgres import (
|
|
22
|
+
PostgresDatabases,
|
|
23
|
+
PostgresRoles,
|
|
24
|
+
make_execute_psql_command,
|
|
25
|
+
make_psql_command,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@operation(is_idempotent=False)
|
|
30
|
+
def sql(
|
|
31
|
+
sql: str,
|
|
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
|
+
psql_database: str | None = None,
|
|
38
|
+
):
|
|
39
|
+
"""
|
|
40
|
+
Execute arbitrary SQL against PostgreSQL.
|
|
41
|
+
|
|
42
|
+
+ sql: SQL command(s) to execute
|
|
43
|
+
+ psql_*: global module arguments, see above
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
yield make_execute_psql_command(
|
|
47
|
+
sql,
|
|
48
|
+
user=psql_user,
|
|
49
|
+
password=psql_password,
|
|
50
|
+
host=psql_host,
|
|
51
|
+
port=psql_port,
|
|
52
|
+
database=psql_database,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@operation()
|
|
57
|
+
def role(
|
|
58
|
+
role: str,
|
|
59
|
+
present: bool = True,
|
|
60
|
+
password: str | None = None,
|
|
61
|
+
login: bool = True,
|
|
62
|
+
superuser: bool = False,
|
|
63
|
+
inherit: bool = False,
|
|
64
|
+
createdb: bool = False,
|
|
65
|
+
createrole: bool = False,
|
|
66
|
+
replication: bool = 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
|
+
psql_database: str | None = None,
|
|
74
|
+
):
|
|
75
|
+
"""
|
|
76
|
+
Add/remove PostgreSQL roles.
|
|
77
|
+
|
|
78
|
+
+ role: name of the role
|
|
79
|
+
+ present: whether the role should be present or absent
|
|
80
|
+
+ password: the password for the role
|
|
81
|
+
+ login: whether the role can login
|
|
82
|
+
+ superuser: whether role will be a superuser
|
|
83
|
+
+ inherit: whether the role inherits from other roles
|
|
84
|
+
+ createdb: whether the role is allowed to create databases
|
|
85
|
+
+ createrole: whether the role is allowed to create new roles
|
|
86
|
+
+ replication: whether this role is allowed to replicate
|
|
87
|
+
+ connection_limit: the connection limit for the role
|
|
88
|
+
+ psql_*: global module arguments, see above
|
|
89
|
+
|
|
90
|
+
Updates:
|
|
91
|
+
pyinfra will not attempt to change existing roles - it will either
|
|
92
|
+
create or drop roles, but not alter them (if the role exists this
|
|
93
|
+
operation will make no changes).
|
|
94
|
+
|
|
95
|
+
**Example:**
|
|
96
|
+
|
|
97
|
+
.. code:: python
|
|
98
|
+
|
|
99
|
+
from pyinfra.operations import postgresql
|
|
100
|
+
postgresql.role(
|
|
101
|
+
name="Create the pyinfra PostgreSQL role",
|
|
102
|
+
role="pyinfra",
|
|
103
|
+
password="somepassword",
|
|
104
|
+
superuser=True,
|
|
105
|
+
login=True,
|
|
106
|
+
_sudo_user="postgres",
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
roles = host.get_fact(
|
|
112
|
+
PostgresRoles,
|
|
113
|
+
psql_user=psql_user,
|
|
114
|
+
psql_password=psql_password,
|
|
115
|
+
psql_host=psql_host,
|
|
116
|
+
psql_port=psql_port,
|
|
117
|
+
psql_database=psql_database,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
is_present = role in roles
|
|
121
|
+
|
|
122
|
+
# User not wanted?
|
|
123
|
+
if not present:
|
|
124
|
+
if is_present:
|
|
125
|
+
yield make_execute_psql_command(
|
|
126
|
+
'DROP ROLE "{0}"'.format(role),
|
|
127
|
+
user=psql_user,
|
|
128
|
+
password=psql_password,
|
|
129
|
+
host=psql_host,
|
|
130
|
+
port=psql_port,
|
|
131
|
+
database=psql_database,
|
|
132
|
+
)
|
|
133
|
+
else:
|
|
134
|
+
host.noop("postgresql role {0} does not exist".format(role))
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
# If we want the user and they don't exist
|
|
138
|
+
if not is_present:
|
|
139
|
+
sql_bits = ['CREATE ROLE "{0}"'.format(role)]
|
|
140
|
+
|
|
141
|
+
for key, value in (
|
|
142
|
+
("LOGIN", login),
|
|
143
|
+
("SUPERUSER", superuser),
|
|
144
|
+
("INHERIT", inherit),
|
|
145
|
+
("CREATEDB", createdb),
|
|
146
|
+
("CREATEROLE", createrole),
|
|
147
|
+
("REPLICATION", replication),
|
|
148
|
+
):
|
|
149
|
+
if value:
|
|
150
|
+
sql_bits.append(key)
|
|
151
|
+
|
|
152
|
+
if connection_limit:
|
|
153
|
+
sql_bits.append("CONNECTION LIMIT {0}".format(connection_limit))
|
|
154
|
+
|
|
155
|
+
if password:
|
|
156
|
+
sql_bits.append(MaskString("PASSWORD '{0}'".format(password)))
|
|
157
|
+
|
|
158
|
+
yield make_execute_psql_command(
|
|
159
|
+
StringCommand(*sql_bits),
|
|
160
|
+
user=psql_user,
|
|
161
|
+
password=psql_password,
|
|
162
|
+
host=psql_host,
|
|
163
|
+
port=psql_port,
|
|
164
|
+
database=psql_database,
|
|
165
|
+
)
|
|
166
|
+
else:
|
|
167
|
+
# Check if any attributes need updating
|
|
168
|
+
current_role = roles[role]
|
|
169
|
+
should_execute = False
|
|
170
|
+
sql_bits = ['ALTER ROLE "{0}"'.format(role)]
|
|
171
|
+
if login and "login" in current_role and current_role["login"] != login:
|
|
172
|
+
sql_bits.append("LOGIN")
|
|
173
|
+
should_execute = True
|
|
174
|
+
if superuser and "superuser" in current_role and current_role["superuser"] != superuser:
|
|
175
|
+
sql_bits.append("SUPERUSER")
|
|
176
|
+
should_execute = True
|
|
177
|
+
if inherit and "inherit" in current_role and current_role["inherit"] != inherit:
|
|
178
|
+
sql_bits.append("INHERIT")
|
|
179
|
+
should_execute = True
|
|
180
|
+
if createdb and "createdb" in current_role and current_role["createdb"] != createdb:
|
|
181
|
+
sql_bits.append("CREATEDB")
|
|
182
|
+
should_execute = True
|
|
183
|
+
if createrole and "createrole" in current_role and current_role["createrole"] != createrole:
|
|
184
|
+
sql_bits.append("CREATEROLE")
|
|
185
|
+
should_execute = True
|
|
186
|
+
if (
|
|
187
|
+
connection_limit
|
|
188
|
+
and "connection_limit" in current_role
|
|
189
|
+
and roles[role]["connection_limit"] != connection_limit
|
|
190
|
+
):
|
|
191
|
+
sql_bits.append("CONNECTION LIMIT {0}".format(connection_limit))
|
|
192
|
+
should_execute = True
|
|
193
|
+
if password:
|
|
194
|
+
sql_bits.append(MaskString("PASSWORD '{0}'".format(password)))
|
|
195
|
+
should_execute = True
|
|
196
|
+
|
|
197
|
+
if should_execute:
|
|
198
|
+
yield make_execute_psql_command(
|
|
199
|
+
StringCommand(*sql_bits),
|
|
200
|
+
user=psql_user,
|
|
201
|
+
password=psql_password,
|
|
202
|
+
host=psql_host,
|
|
203
|
+
port=psql_port,
|
|
204
|
+
database=psql_database,
|
|
205
|
+
)
|
|
206
|
+
else:
|
|
207
|
+
host.noop("postgresql role {0} exists and does not need updates".format(role))
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
@operation()
|
|
211
|
+
def database(
|
|
212
|
+
database: str,
|
|
213
|
+
present=True,
|
|
214
|
+
owner: str | None = None,
|
|
215
|
+
template: str | None = None,
|
|
216
|
+
encoding: str | None = None,
|
|
217
|
+
lc_collate: str | None = None,
|
|
218
|
+
lc_ctype: str | None = None,
|
|
219
|
+
tablespace: str | None = None,
|
|
220
|
+
connection_limit: int | None = None,
|
|
221
|
+
# Details for speaking to PostgreSQL via `psql` CLI
|
|
222
|
+
psql_user: str | None = None,
|
|
223
|
+
psql_password: str | None = None,
|
|
224
|
+
psql_host: str | None = None,
|
|
225
|
+
psql_port: int | None = None,
|
|
226
|
+
psql_database: str | None = None,
|
|
227
|
+
):
|
|
228
|
+
"""
|
|
229
|
+
Add/remove PostgreSQL databases.
|
|
230
|
+
|
|
231
|
+
+ name: name of the database
|
|
232
|
+
+ present: whether the database should exist or not
|
|
233
|
+
+ owner: the PostgreSQL role that owns the database
|
|
234
|
+
+ template: name of the PostgreSQL template to use
|
|
235
|
+
+ encoding: encoding of the database
|
|
236
|
+
+ lc_collate: lc_collate of the database
|
|
237
|
+
+ lc_ctype: lc_ctype of the database
|
|
238
|
+
+ tablespace: the tablespace to use for the template
|
|
239
|
+
+ connection_limit: the connection limit to apply to the database
|
|
240
|
+
+ psql_*: global module arguments, see above
|
|
241
|
+
|
|
242
|
+
Updates:
|
|
243
|
+
pyinfra will change existing databases - but some parameters are not
|
|
244
|
+
changeable (template, encoding, lc_collate and lc_ctype).
|
|
245
|
+
|
|
246
|
+
**Example:**
|
|
247
|
+
|
|
248
|
+
.. code:: python
|
|
249
|
+
|
|
250
|
+
postgresql.database(
|
|
251
|
+
name="Create the pyinfra_stuff database",
|
|
252
|
+
database="pyinfra_stuff",
|
|
253
|
+
owner="pyinfra",
|
|
254
|
+
encoding="UTF8",
|
|
255
|
+
_sudo_user="postgres",
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
"""
|
|
259
|
+
|
|
260
|
+
current_databases = host.get_fact(
|
|
261
|
+
PostgresDatabases,
|
|
262
|
+
psql_user=psql_user,
|
|
263
|
+
psql_password=psql_password,
|
|
264
|
+
psql_host=psql_host,
|
|
265
|
+
psql_port=psql_port,
|
|
266
|
+
psql_database=psql_database,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
is_present = database in current_databases
|
|
270
|
+
|
|
271
|
+
if not present:
|
|
272
|
+
if is_present:
|
|
273
|
+
yield make_execute_psql_command(
|
|
274
|
+
'DROP DATABASE "{0}"'.format(database),
|
|
275
|
+
user=psql_user,
|
|
276
|
+
password=psql_password,
|
|
277
|
+
host=psql_host,
|
|
278
|
+
port=psql_port,
|
|
279
|
+
database=psql_database,
|
|
280
|
+
)
|
|
281
|
+
else:
|
|
282
|
+
host.noop("postgresql database {0} does not exist".format(database))
|
|
283
|
+
return
|
|
284
|
+
|
|
285
|
+
# We want the database but it doesn't exist
|
|
286
|
+
if present and not is_present:
|
|
287
|
+
sql_bits = ['CREATE DATABASE "{0}"'.format(database)]
|
|
288
|
+
|
|
289
|
+
for key, value in (
|
|
290
|
+
("OWNER", '"{0}"'.format(owner) if owner else owner),
|
|
291
|
+
("TEMPLATE", template),
|
|
292
|
+
("ENCODING", encoding),
|
|
293
|
+
("LC_COLLATE", "'{0}'".format(lc_collate) if lc_collate else lc_collate),
|
|
294
|
+
("LC_CTYPE", "'{0}'".format(lc_ctype) if lc_ctype else lc_ctype),
|
|
295
|
+
("TABLESPACE", tablespace),
|
|
296
|
+
("CONNECTION LIMIT", connection_limit),
|
|
297
|
+
):
|
|
298
|
+
if value:
|
|
299
|
+
sql_bits.append("{0} {1}".format(key, value))
|
|
300
|
+
|
|
301
|
+
yield make_execute_psql_command(
|
|
302
|
+
StringCommand(*sql_bits),
|
|
303
|
+
user=psql_user,
|
|
304
|
+
password=psql_password,
|
|
305
|
+
host=psql_host,
|
|
306
|
+
port=psql_port,
|
|
307
|
+
database=psql_database,
|
|
308
|
+
)
|
|
309
|
+
else:
|
|
310
|
+
current_db = current_databases[database]
|
|
311
|
+
|
|
312
|
+
for key, value, current_value in (
|
|
313
|
+
("TEMPLATE", template, current_db.get("istemplate")),
|
|
314
|
+
("ENCODING", encoding, current_db.get("encoding")),
|
|
315
|
+
("LC_COLLATE", lc_collate, None),
|
|
316
|
+
("LC_CTYPE", lc_ctype, None),
|
|
317
|
+
):
|
|
318
|
+
if value and (current_value is None or current_value != value):
|
|
319
|
+
host.noop(
|
|
320
|
+
"postgresql database {0} already exists, skipping {1}".format(database, key)
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
sql_bits = []
|
|
324
|
+
|
|
325
|
+
if owner and "owner" in current_db and current_db["owner"] != owner:
|
|
326
|
+
sql_bits.append('ALTER DATABASE "{0}" OWNER TO "{1}";'.format(database, owner))
|
|
327
|
+
|
|
328
|
+
if tablespace and "tablespace" in current_db and current_db["tablespace"] != tablespace:
|
|
329
|
+
sql_bits.append(
|
|
330
|
+
'ALTER DATABASE "{0}" SET TABLESPACE "{1}";'.format(database, tablespace)
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
if (
|
|
334
|
+
connection_limit
|
|
335
|
+
and "connlimit" in current_db
|
|
336
|
+
and current_db["connlimit"] != connection_limit
|
|
337
|
+
):
|
|
338
|
+
sql_bits.append(
|
|
339
|
+
'ALTER DATABASE "{0}" CONNECTION LIMIT {1};'.format(database, connection_limit)
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
if len(sql_bits) > 0:
|
|
343
|
+
yield make_execute_psql_command(
|
|
344
|
+
StringCommand(*sql_bits),
|
|
345
|
+
user=psql_user,
|
|
346
|
+
password=psql_password,
|
|
347
|
+
host=psql_host,
|
|
348
|
+
port=psql_port,
|
|
349
|
+
database=psql_database,
|
|
350
|
+
)
|
|
351
|
+
else:
|
|
352
|
+
host.noop(
|
|
353
|
+
"postgresql database {0} already exists with the same parameters".format(database)
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
@operation(is_idempotent=False)
|
|
358
|
+
def dump(
|
|
359
|
+
dest: str,
|
|
360
|
+
# Details for speaking to PostgreSQL via `psql` CLI
|
|
361
|
+
psql_user: str | None = None,
|
|
362
|
+
psql_password: str | None = None,
|
|
363
|
+
psql_host: str | None = None,
|
|
364
|
+
psql_port: int | None = None,
|
|
365
|
+
psql_database: str | None = None,
|
|
366
|
+
):
|
|
367
|
+
"""
|
|
368
|
+
Dump a PostgreSQL database into a ``.sql`` file. Requires ``pg_dump``.
|
|
369
|
+
|
|
370
|
+
+ dest: name of the file to dump the SQL to
|
|
371
|
+
+ psql_*: global module arguments, see above
|
|
372
|
+
|
|
373
|
+
**Example:**
|
|
374
|
+
|
|
375
|
+
.. code:: python
|
|
376
|
+
|
|
377
|
+
postgresql.dump(
|
|
378
|
+
name="Dump the pyinfra_stuff database",
|
|
379
|
+
dest="/tmp/pyinfra_stuff.dump",
|
|
380
|
+
sudo_user="postgres",
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
"""
|
|
384
|
+
|
|
385
|
+
yield StringCommand(
|
|
386
|
+
make_psql_command(
|
|
387
|
+
executable="pg_dump",
|
|
388
|
+
user=psql_user,
|
|
389
|
+
password=psql_password,
|
|
390
|
+
host=psql_host,
|
|
391
|
+
port=psql_port,
|
|
392
|
+
database=psql_database,
|
|
393
|
+
),
|
|
394
|
+
">",
|
|
395
|
+
QuoteString(dest),
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
@operation(is_idempotent=False)
|
|
400
|
+
def load(
|
|
401
|
+
src: str,
|
|
402
|
+
# Details for speaking to PostgreSQL via `psql` CLI
|
|
403
|
+
psql_user: str | None = None,
|
|
404
|
+
psql_password: str | None = None,
|
|
405
|
+
psql_host: str | None = None,
|
|
406
|
+
psql_port: int | None = None,
|
|
407
|
+
psql_database: str | None = None,
|
|
408
|
+
):
|
|
409
|
+
"""
|
|
410
|
+
Load ``.sql`` file into a database.
|
|
411
|
+
|
|
412
|
+
+ src: the filename to read from
|
|
413
|
+
+ psql_*: global module arguments, see above
|
|
414
|
+
|
|
415
|
+
**Example:**
|
|
416
|
+
|
|
417
|
+
.. code:: python
|
|
418
|
+
|
|
419
|
+
postgresql.load(
|
|
420
|
+
name="Import the pyinfra_stuff dump into pyinfra_stuff_copy",
|
|
421
|
+
src="/tmp/pyinfra_stuff.dump",
|
|
422
|
+
sudo_user="postgres",
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
"""
|
|
426
|
+
|
|
427
|
+
yield StringCommand(
|
|
428
|
+
make_psql_command(
|
|
429
|
+
user=psql_user,
|
|
430
|
+
password=psql_password,
|
|
431
|
+
host=psql_host,
|
|
432
|
+
port=psql_port,
|
|
433
|
+
database=psql_database,
|
|
434
|
+
),
|
|
435
|
+
"<",
|
|
436
|
+
QuoteString(src),
|
|
437
|
+
)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pyinfra.api import operation
|
|
4
|
+
|
|
5
|
+
from . import postgres
|
|
6
|
+
|
|
7
|
+
|
|
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)
|
|
11
|
+
|
|
12
|
+
|
|
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)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@operation(is_idempotent=False, is_deprecated=True)
|
|
19
|
+
def database(*args, **kwargs):
|
|
20
|
+
yield from postgres.database._inner(*args, **kwargs)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@operation(is_idempotent=False, is_deprecated=True)
|
|
24
|
+
def dump(*args, **kwargs):
|
|
25
|
+
yield from postgres.dump._inner(*args, **kwargs)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@operation(is_idempotent=False, is_deprecated=True)
|
|
29
|
+
def load(*args, **kwargs):
|
|
30
|
+
yield from postgres.load._inner(*args, **kwargs)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pyinfra.api import operation
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@operation(is_idempotent=False)
|
|
7
|
+
def agent(server: str | None = None, port: int | None = None):
|
|
8
|
+
"""
|
|
9
|
+
Run puppet agent
|
|
10
|
+
|
|
11
|
+
+ server: master server URL
|
|
12
|
+
+ port: puppet master port
|
|
13
|
+
|
|
14
|
+
Note: Either 'USE_SUDO_LOGIN=True' or 'USE_SU_LOGIN=True'
|
|
15
|
+
for puppet.agent() as `puppet` is added to the path in
|
|
16
|
+
the .bash_profile.
|
|
17
|
+
|
|
18
|
+
**Example:**
|
|
19
|
+
|
|
20
|
+
.. code:: python
|
|
21
|
+
|
|
22
|
+
from pyinfra.operations import puppet
|
|
23
|
+
puppet.agent()
|
|
24
|
+
|
|
25
|
+
# We also expect a return code of:
|
|
26
|
+
# 0=no changes or 2=changes applied
|
|
27
|
+
puppet.agent(
|
|
28
|
+
name="Run the puppet agent",
|
|
29
|
+
success_exit_codes=[0, 2],
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
args = []
|
|
35
|
+
|
|
36
|
+
if server:
|
|
37
|
+
args.append("--server=%s" % server)
|
|
38
|
+
if port:
|
|
39
|
+
args.append("--masterport=%s" % port)
|
|
40
|
+
|
|
41
|
+
yield "puppet agent -t %s" % " ".join(args)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The Python module allows you to execute Python code within the context of a deploy.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import Callable
|
|
8
|
+
|
|
9
|
+
from pyinfra.api import FunctionCommand, operation
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@operation(is_idempotent=False, _set_in_op=False)
|
|
13
|
+
def call(function: Callable, *args, **kwargs):
|
|
14
|
+
"""
|
|
15
|
+
Execute a Python function within a deploy.
|
|
16
|
+
|
|
17
|
+
+ function: the function to execute
|
|
18
|
+
+ args: arguments to pass to the function
|
|
19
|
+
+ kwargs: keyword arguments to pass to the function
|
|
20
|
+
|
|
21
|
+
**Example:**
|
|
22
|
+
|
|
23
|
+
.. code:: python
|
|
24
|
+
|
|
25
|
+
from pyinfra.operations import python
|
|
26
|
+
def my_callback(hello=None):
|
|
27
|
+
command = 'echo hello'
|
|
28
|
+
if hello:
|
|
29
|
+
command = command + ' ' + hello
|
|
30
|
+
|
|
31
|
+
status, stdout, stderr = host.run_shell_command(command=command, sudo=SUDO)
|
|
32
|
+
assert status is True # ensure the command executed OK
|
|
33
|
+
|
|
34
|
+
if 'hello ' not in '\\n'.join(stdout): # stdout/stderr is a *list* of lines
|
|
35
|
+
raise Exception(
|
|
36
|
+
f'`{command}` problem with callback stdout:{stdout} stderr:{stderr}',
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
python.call(
|
|
40
|
+
name="Run my_callback function",
|
|
41
|
+
function=my_callback,
|
|
42
|
+
hello="world",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
yield FunctionCommand(function, args, kwargs)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@operation(is_idempotent=False, _set_in_op=False)
|
|
51
|
+
def raise_exception(exception: Exception, *args, **kwargs):
|
|
52
|
+
"""
|
|
53
|
+
Raise a Python exception within a deploy.
|
|
54
|
+
|
|
55
|
+
+ exception: the exception class to raise
|
|
56
|
+
+ args: arguments passed to the exception creation
|
|
57
|
+
+ kwargs: keyword arguments passed to the exception creation
|
|
58
|
+
|
|
59
|
+
**Example**:
|
|
60
|
+
|
|
61
|
+
.. code:: python
|
|
62
|
+
|
|
63
|
+
python.raise_exception(
|
|
64
|
+
name="Raise NotImplementedError exception",
|
|
65
|
+
exception=NotImplementedError,
|
|
66
|
+
message="This is not implemented",
|
|
67
|
+
)
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
def raise_exc(*args, **kwargs): # pragma: no cover
|
|
71
|
+
raise exception(*args, **kwargs) # type: ignore[operator]
|
|
72
|
+
|
|
73
|
+
yield FunctionCommand(raise_exc, args, kwargs)
|