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.
Files changed (115) hide show
  1. pyinfra/api/__init__.py +3 -0
  2. pyinfra/api/arguments.py +12 -5
  3. pyinfra/api/arguments_typed.py +19 -6
  4. pyinfra/api/command.py +5 -3
  5. pyinfra/api/config.py +115 -13
  6. pyinfra/api/connectors.py +5 -2
  7. pyinfra/api/exceptions.py +19 -0
  8. pyinfra/api/facts.py +34 -33
  9. pyinfra/api/host.py +51 -12
  10. pyinfra/api/inventory.py +4 -0
  11. pyinfra/api/operation.py +88 -42
  12. pyinfra/api/operations.py +10 -11
  13. pyinfra/api/state.py +11 -2
  14. pyinfra/api/util.py +24 -16
  15. pyinfra/connectors/base.py +4 -7
  16. pyinfra/connectors/chroot.py +5 -6
  17. pyinfra/connectors/docker.py +13 -19
  18. pyinfra/connectors/dockerssh.py +5 -4
  19. pyinfra/connectors/local.py +7 -7
  20. pyinfra/connectors/ssh.py +46 -25
  21. pyinfra/connectors/terraform.py +9 -6
  22. pyinfra/connectors/util.py +7 -8
  23. pyinfra/connectors/vagrant.py +11 -10
  24. pyinfra/context.py +1 -0
  25. pyinfra/facts/apk.py +2 -0
  26. pyinfra/facts/apt.py +2 -0
  27. pyinfra/facts/brew.py +2 -0
  28. pyinfra/facts/bsdinit.py +2 -0
  29. pyinfra/facts/cargo.py +2 -0
  30. pyinfra/facts/choco.py +3 -1
  31. pyinfra/facts/deb.py +9 -4
  32. pyinfra/facts/dnf.py +2 -0
  33. pyinfra/facts/docker.py +2 -0
  34. pyinfra/facts/files.py +2 -0
  35. pyinfra/facts/gem.py +2 -0
  36. pyinfra/facts/gpg.py +2 -0
  37. pyinfra/facts/hardware.py +30 -22
  38. pyinfra/facts/launchd.py +2 -0
  39. pyinfra/facts/lxd.py +2 -0
  40. pyinfra/facts/mysql.py +12 -6
  41. pyinfra/facts/npm.py +1 -0
  42. pyinfra/facts/openrc.py +2 -0
  43. pyinfra/facts/pacman.py +6 -2
  44. pyinfra/facts/pip.py +2 -0
  45. pyinfra/facts/pkg.py +2 -0
  46. pyinfra/facts/pkgin.py +2 -0
  47. pyinfra/facts/postgres.py +168 -0
  48. pyinfra/facts/postgresql.py +5 -162
  49. pyinfra/facts/rpm.py +12 -9
  50. pyinfra/facts/server.py +10 -13
  51. pyinfra/facts/snap.py +2 -0
  52. pyinfra/facts/systemd.py +28 -10
  53. pyinfra/facts/upstart.py +2 -0
  54. pyinfra/facts/util/packaging.py +3 -2
  55. pyinfra/facts/vzctl.py +2 -0
  56. pyinfra/facts/xbps.py +2 -0
  57. pyinfra/facts/yum.py +2 -0
  58. pyinfra/facts/zypper.py +2 -0
  59. pyinfra/operations/apk.py +3 -1
  60. pyinfra/operations/apt.py +16 -18
  61. pyinfra/operations/brew.py +10 -8
  62. pyinfra/operations/bsdinit.py +5 -3
  63. pyinfra/operations/cargo.py +3 -1
  64. pyinfra/operations/choco.py +3 -1
  65. pyinfra/operations/dnf.py +15 -19
  66. pyinfra/operations/files.py +86 -69
  67. pyinfra/operations/gem.py +3 -1
  68. pyinfra/operations/git.py +18 -16
  69. pyinfra/operations/iptables.py +33 -25
  70. pyinfra/operations/launchd.py +5 -6
  71. pyinfra/operations/lxd.py +7 -4
  72. pyinfra/operations/mysql.py +57 -53
  73. pyinfra/operations/npm.py +8 -1
  74. pyinfra/operations/openrc.py +5 -3
  75. pyinfra/operations/pacman.py +4 -5
  76. pyinfra/operations/pip.py +16 -9
  77. pyinfra/operations/pkg.py +3 -1
  78. pyinfra/operations/pkgin.py +3 -1
  79. pyinfra/operations/postgres.py +349 -0
  80. pyinfra/operations/postgresql.py +18 -335
  81. pyinfra/operations/puppet.py +3 -1
  82. pyinfra/operations/python.py +7 -3
  83. pyinfra/operations/selinux.py +42 -16
  84. pyinfra/operations/server.py +48 -43
  85. pyinfra/operations/snap.py +3 -1
  86. pyinfra/operations/ssh.py +12 -10
  87. pyinfra/operations/systemd.py +13 -9
  88. pyinfra/operations/sysvinit.py +6 -4
  89. pyinfra/operations/upstart.py +5 -3
  90. pyinfra/operations/util/files.py +24 -16
  91. pyinfra/operations/util/packaging.py +53 -37
  92. pyinfra/operations/util/service.py +18 -13
  93. pyinfra/operations/vzctl.py +12 -10
  94. pyinfra/operations/xbps.py +3 -1
  95. pyinfra/operations/yum.py +14 -18
  96. pyinfra/operations/zypper.py +8 -9
  97. pyinfra/version.py +5 -2
  98. {pyinfra-3.0b0.dist-info → pyinfra-3.0b2.dist-info}/METADATA +31 -29
  99. pyinfra-3.0b2.dist-info/RECORD +163 -0
  100. {pyinfra-3.0b0.dist-info → pyinfra-3.0b2.dist-info}/WHEEL +1 -1
  101. pyinfra_cli/commands.py +3 -2
  102. pyinfra_cli/inventory.py +38 -19
  103. pyinfra_cli/main.py +2 -0
  104. pyinfra_cli/prints.py +27 -105
  105. pyinfra_cli/util.py +3 -1
  106. tests/test_api/test_api_deploys.py +5 -5
  107. tests/test_api/test_api_operations.py +5 -5
  108. tests/test_connectors/test_ssh.py +105 -0
  109. tests/test_connectors/test_terraform.py +11 -8
  110. tests/test_connectors/test_vagrant.py +6 -6
  111. pyinfra-3.0b0.dist-info/RECORD +0 -162
  112. pyinfra_cli/inventory_dsl.py +0 -23
  113. {pyinfra-3.0b0.dist-info → pyinfra-3.0b2.dist-info}/LICENSE.md +0 -0
  114. {pyinfra-3.0b0.dist-info → pyinfra-3.0b2.dist-info}/entry_points.txt +0 -0
  115. {pyinfra-3.0b0.dist-info → pyinfra-3.0b2.dist-info}/top_level.txt +0 -0
@@ -1,347 +1,30 @@
1
- """
2
- The PostgreSQL modules manage PostgreSQL databases, users and privileges.
1
+ from __future__ import annotations
3
2
 
4
- Requires the ``psql`` CLI executable on the target host(s).
3
+ from pyinfra.api import operation
5
4
 
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
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
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
 
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)
25
16
 
26
- @operation(is_idempotent=False)
27
- def sql(
28
- sql,
29
- database=None,
30
- # Details for speaking to PostgreSQL via `psql` CLI
31
- psql_user=None,
32
- psql_password=None,
33
- psql_host=None,
34
- psql_port=None,
35
- ):
36
- """
37
- Execute arbitrary SQL against PostgreSQL.
38
17
 
39
- + sql: SQL command(s) to execute
40
- + database: optional database to execute against
41
- + psql_*: global module arguments, see above
42
- """
18
+ @operation(is_idempotent=False, is_deprecated=True)
19
+ def database(*args, **kwargs):
20
+ yield from postgres.database._inner(*args, **kwargs)
43
21
 
44
- yield make_execute_psql_command(
45
- sql,
46
- database=database,
47
- user=psql_user,
48
- password=psql_password,
49
- host=psql_host,
50
- port=psql_port,
51
- )
52
22
 
23
+ @operation(is_idempotent=False, is_deprecated=True)
24
+ def dump(*args, **kwargs):
25
+ yield from postgres.dump._inner(*args, **kwargs)
53
26
 
54
- @operation()
55
- def role(
56
- role,
57
- present=True,
58
- password=None,
59
- login=True,
60
- superuser=False,
61
- inherit=False,
62
- createdb=False,
63
- createrole=False,
64
- replication=False,
65
- connection_limit=None,
66
- # Details for speaking to PostgreSQL via `psql` CLI
67
- psql_user=None,
68
- psql_password=None,
69
- psql_host=None,
70
- psql_port=None,
71
- ):
72
- """
73
- Add/remove PostgreSQL roles.
74
27
 
75
- + role: name of the role
76
- + present: whether the role should be present or absent
77
- + password: the password for the role
78
- + login: whether the role can login
79
- + superuser: whether role will be a superuser
80
- + inherit: whether the role inherits from other roles
81
- + createdb: whether the role is allowed to create databases
82
- + createrole: whether the role is allowed to create new roles
83
- + replication: whether this role is allowed to replicate
84
- + connection_limit: the connection limit for the role
85
- + psql_*: global module arguments, see above
86
-
87
- Updates:
88
- pyinfra will not attempt to change existing roles - it will either
89
- create or drop roles, but not alter them (if the role exists this
90
- operation will make no changes).
91
-
92
- **Example:**
93
-
94
- .. code:: python
95
-
96
- postgresql.role(
97
- name="Create the pyinfra PostgreSQL role",
98
- role="pyinfra",
99
- password="somepassword",
100
- superuser=True,
101
- login=True,
102
- sudo_user="postgres",
103
- )
104
-
105
- """
106
-
107
- roles = host.get_fact(
108
- PostgresqlRoles,
109
- psql_user=psql_user,
110
- psql_password=psql_password,
111
- psql_host=psql_host,
112
- psql_port=psql_port,
113
- )
114
-
115
- is_present = role in roles
116
-
117
- # User not wanted?
118
- if not present:
119
- if is_present:
120
- yield make_execute_psql_command(
121
- 'DROP ROLE "{0}"'.format(role),
122
- user=psql_user,
123
- password=psql_password,
124
- host=psql_host,
125
- port=psql_port,
126
- )
127
- else:
128
- host.noop("postgresql role {0} does not exist".format(role))
129
- return
130
-
131
- # If we want the user and they don't exist
132
- if not is_present:
133
- sql_bits = ['CREATE ROLE "{0}"'.format(role)]
134
-
135
- for key, value in (
136
- ("LOGIN", login),
137
- ("SUPERUSER", superuser),
138
- ("INHERIT", inherit),
139
- ("CREATEDB", createdb),
140
- ("CREATEROLE", createrole),
141
- ("REPLICATION", replication),
142
- ):
143
- if value:
144
- sql_bits.append(key)
145
-
146
- if connection_limit:
147
- sql_bits.append("CONNECTION LIMIT {0}".format(connection_limit))
148
-
149
- if password:
150
- sql_bits.append(MaskString("PASSWORD '{0}'".format(password)))
151
-
152
- yield make_execute_psql_command(
153
- StringCommand(*sql_bits),
154
- user=psql_user,
155
- password=psql_password,
156
- host=psql_host,
157
- port=psql_port,
158
- )
159
- else:
160
- host.noop("postgresql role {0} exists".format(role))
161
-
162
-
163
- @operation()
164
- def database(
165
- database,
166
- present=True,
167
- owner=None,
168
- template=None,
169
- encoding=None,
170
- lc_collate=None,
171
- lc_ctype=None,
172
- tablespace=None,
173
- connection_limit=None,
174
- # Details for speaking to PostgreSQL via `psql` CLI
175
- psql_user=None,
176
- psql_password=None,
177
- psql_host=None,
178
- psql_port=None,
179
- ):
180
- """
181
- Add/remove PostgreSQL databases.
182
-
183
- + name: name of the database
184
- + present: whether the database should exist or not
185
- + owner: the PostgreSQL role that owns the database
186
- + template: name of the PostgreSQL template to use
187
- + encoding: encoding of the database
188
- + lc_collate: lc_collate of the database
189
- + lc_ctype: lc_ctype of the database
190
- + tablespace: the tablespace to use for the template
191
- + connection_limit: the connection limit to apply to the database
192
- + psql_*: global module arguments, see above
193
-
194
- Updates:
195
- pyinfra will not attempt to change existing databases - it will either
196
- create or drop databases, but not alter them (if the db exists this
197
- operation will make no changes).
198
-
199
- **Example:**
200
-
201
- .. code:: python
202
-
203
- postgresql.database(
204
- name="Create the pyinfra_stuff database",
205
- database="pyinfra_stuff",
206
- owner="pyinfra",
207
- encoding="UTF8",
208
- sudo_user="postgres",
209
- )
210
-
211
- """
212
-
213
- current_databases = host.get_fact(
214
- PostgresqlDatabases,
215
- psql_user=psql_user,
216
- psql_password=psql_password,
217
- psql_host=psql_host,
218
- psql_port=psql_port,
219
- )
220
-
221
- is_present = database in current_databases
222
-
223
- if not present:
224
- if is_present:
225
- yield make_execute_psql_command(
226
- 'DROP DATABASE "{0}"'.format(database),
227
- user=psql_user,
228
- password=psql_password,
229
- host=psql_host,
230
- port=psql_port,
231
- )
232
- else:
233
- host.noop("postgresql database {0} does not exist".format(database))
234
- return
235
-
236
- # We want the database but it doesn't exist
237
- if present and not is_present:
238
- sql_bits = ['CREATE DATABASE "{0}"'.format(database)]
239
-
240
- for key, value in (
241
- ("OWNER", '"{0}"'.format(owner) if owner else owner),
242
- ("TEMPLATE", template),
243
- ("ENCODING", encoding),
244
- ("LC_COLLATE", lc_collate),
245
- ("LC_CTYPE", lc_ctype),
246
- ("TABLESPACE", tablespace),
247
- ("CONNECTION LIMIT", connection_limit),
248
- ):
249
- if value:
250
- sql_bits.append("{0} {1}".format(key, value))
251
-
252
- yield make_execute_psql_command(
253
- StringCommand(*sql_bits),
254
- user=psql_user,
255
- password=psql_password,
256
- host=psql_host,
257
- port=psql_port,
258
- )
259
- else:
260
- host.noop("postgresql database {0} exists".format(database))
261
-
262
-
263
- @operation(is_idempotent=False)
264
- def dump(
265
- dest,
266
- database=None,
267
- # Details for speaking to PostgreSQL via `psql` CLI
268
- psql_user=None,
269
- psql_password=None,
270
- psql_host=None,
271
- psql_port=None,
272
- ):
273
- """
274
- Dump a PostgreSQL database into a ``.sql`` file. Requires ``pg_dump``.
275
-
276
- + dest: name of the file to dump the SQL to
277
- + database: name of the database to dump
278
- + psql_*: global module arguments, see above
279
-
280
- **Example:**
281
-
282
- .. code:: python
283
-
284
- postgresql.dump(
285
- name="Dump the pyinfra_stuff database",
286
- dest="/tmp/pyinfra_stuff.dump",
287
- database="pyinfra_stuff",
288
- sudo_user="postgres",
289
- )
290
-
291
- """
292
-
293
- yield StringCommand(
294
- make_psql_command(
295
- executable="pg_dump",
296
- database=database,
297
- user=psql_user,
298
- password=psql_password,
299
- host=psql_host,
300
- port=psql_port,
301
- ),
302
- ">",
303
- dest,
304
- )
305
-
306
-
307
- @operation(is_idempotent=False)
308
- def load(
309
- src,
310
- database=None,
311
- # Details for speaking to PostgreSQL via `psql` CLI
312
- psql_user=None,
313
- psql_password=None,
314
- psql_host=None,
315
- psql_port=None,
316
- ):
317
- """
318
- Load ``.sql`` file into a database.
319
-
320
- + src: the filename to read from
321
- + database: name of the database to import into
322
- + psql_*: global module arguments, see above
323
-
324
- **Example:**
325
-
326
- .. code:: python
327
-
328
- postgresql.load(
329
- name="Import the pyinfra_stuff dump into pyinfra_stuff_copy",
330
- src="/tmp/pyinfra_stuff.dump",
331
- database="pyinfra_stuff_copy",
332
- sudo_user="postgres",
333
- )
334
-
335
- """
336
-
337
- yield StringCommand(
338
- make_psql_command(
339
- database=database,
340
- user=psql_user,
341
- password=psql_password,
342
- host=psql_host,
343
- port=psql_port,
344
- ),
345
- "<",
346
- src,
347
- )
28
+ @operation(is_idempotent=False, is_deprecated=True)
29
+ def load(*args, **kwargs):
30
+ yield from postgres.load._inner(*args, **kwargs)
@@ -1,8 +1,10 @@
1
+ from __future__ import annotations
2
+
1
3
  from pyinfra.api import operation
2
4
 
3
5
 
4
6
  @operation(is_idempotent=False)
5
- def agent(server=None, port=None):
7
+ def agent(server: str | None = None, port: int | None = None):
6
8
  """
7
9
  Run puppet agent
8
10
 
@@ -2,11 +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 __future__ import annotations
6
+
7
+ from typing import Callable
8
+
5
9
  from pyinfra.api import FunctionCommand, operation
6
10
 
7
11
 
8
12
  @operation(is_idempotent=False, _set_in_op=False)
9
- def call(function, *args, **kwargs):
13
+ def call(function: Callable, *args, **kwargs):
10
14
  """
11
15
  Execute a Python function within a deploy.
12
16
 
@@ -43,7 +47,7 @@ def call(function, *args, **kwargs):
43
47
 
44
48
 
45
49
  @operation(is_idempotent=False, _set_in_op=False)
46
- def raise_exception(exception, *args, **kwargs):
50
+ def raise_exception(exception: Exception, *args, **kwargs):
47
51
  """
48
52
  Raise a Python exception within a deploy.
49
53
 
@@ -63,6 +67,6 @@ def raise_exception(exception, *args, **kwargs):
63
67
  """
64
68
 
65
69
  def raise_exc(*args, **kwargs): # pragma: no cover
66
- raise exception(*args, **kwargs)
70
+ raise exception(*args, **kwargs) # type: ignore[operator]
67
71
 
68
72
  yield FunctionCommand(raise_exc, args, kwargs)
@@ -1,19 +1,36 @@
1
1
  """
2
2
  Provides operations to set SELinux file contexts, booleans and port types.
3
3
  """
4
+
5
+ from __future__ import annotations
6
+
7
+ from enum import Enum
8
+
4
9
  from pyinfra import host
5
- from pyinfra.api import QuoteString, StringCommand, operation
10
+ from pyinfra.api import OperationValueError, QuoteString, StringCommand, operation
6
11
  from pyinfra.facts.selinux import FileContext, FileContextMapping, SEBoolean, SEPort, SEPorts
7
12
  from pyinfra.facts.server import Which
8
13
 
9
14
 
15
+ class Boolean(Enum):
16
+ ON = "on"
17
+ OFF = "off"
18
+
19
+
20
+ class Protocol(Enum):
21
+ UDP = "udp"
22
+ TCP = "tcp"
23
+ SCTP = "sctp"
24
+ DCCP = "dccp"
25
+
26
+
10
27
  @operation()
11
- def boolean(bool_name, value, persistent=False):
28
+ def boolean(bool_name: str, value: Boolean, persistent=False):
12
29
  """
13
30
  Set the specified SELinux boolean to the desired state.
14
31
 
15
32
  + boolean: name of an SELinux boolean
16
- + state: 'on' or 'off'
33
+ + value: desired state of the boolean
17
34
  + persistent: whether to write updated policy or not
18
35
 
19
36
  Note: This operation requires root privileges.
@@ -25,26 +42,31 @@ def boolean(bool_name, value, persistent=False):
25
42
  selinux.boolean(
26
43
  name='Allow Apache to connect to LDAP server',
27
44
  'httpd_can_network_connect',
28
- 'on',
45
+ Boolean.ON,
29
46
  persistent=True
30
47
  )
31
48
  """
32
- _valid_states = ["on", "off"]
33
49
 
34
- if value not in _valid_states:
35
- raise ValueError(
36
- f'\'value\' must be one of \'{",".join(_valid_states)}\' but found \'{value}\'',
37
- )
50
+ value_str: str
51
+ if value in ["on", "off"]: # compatibility with the old version
52
+ assert isinstance(value, str)
53
+ value_str = value
54
+ elif value is Boolean.ON:
55
+ value_str = "on"
56
+ elif value is Boolean.OFF:
57
+ value_str = "off"
58
+ else:
59
+ raise OperationValueError(f"Invalid value '{value}' for boolean operation")
38
60
 
39
- if host.get_fact(SEBoolean, boolean=bool_name) != value:
61
+ if host.get_fact(SEBoolean, boolean=bool_name) != value_str:
40
62
  persist = "-P " if persistent else ""
41
- yield StringCommand("setsebool", f"{persist}{bool_name}", value)
63
+ yield StringCommand("setsebool", f"{persist}{bool_name}", value_str)
42
64
  else:
43
- host.noop(f"boolean '{bool_name}' already had the value '{value}'")
65
+ host.noop(f"boolean '{bool_name}' already had the value '{value_str}'")
44
66
 
45
67
 
46
68
  @operation()
47
- def file_context(path, se_type):
69
+ def file_context(path: str, se_type: str):
48
70
  """
49
71
  Set the SELinux type for the specified path to the specified value.
50
72
 
@@ -70,7 +92,7 @@ def file_context(path, se_type):
70
92
 
71
93
 
72
94
  @operation()
73
- def file_context_mapping(target, se_type=None, present=True):
95
+ def file_context_mapping(target: str, se_type: str | None = None, present=True):
74
96
  """
75
97
  Set the SELinux file context mapping for paths matching the target.
76
98
 
@@ -110,7 +132,7 @@ def file_context_mapping(target, se_type=None, present=True):
110
132
 
111
133
 
112
134
  @operation()
113
- def port(protocol, port_num, se_type=None, present=True):
135
+ def port(protocol: Protocol | str, port_num: int, se_type: str | None = None, present=True):
114
136
  """
115
137
  Set the SELinux type for the specified protocol and port.
116
138
 
@@ -127,12 +149,16 @@ def port(protocol, port_num, se_type=None, present=True):
127
149
 
128
150
  selinux.port(
129
151
  name='Allow Apache to provide service on port 2222',
130
- 'tcp',
152
+ Protocol.TCP,
131
153
  2222,
132
154
  'http_port_t',
133
155
  )
134
156
  """
135
157
 
158
+ if protocol is Protocol:
159
+ assert isinstance(protocol, Protocol)
160
+ protocol = protocol.value
161
+
136
162
  if present and (se_type is None):
137
163
  raise ValueError("se_type must have a valid value if present is set")
138
164