pyinfra 2.9.2__py2.py3-none-any.whl → 3.0b1__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 +261 -255
- pyinfra/api/arguments_typed.py +77 -0
- pyinfra/api/command.py +66 -53
- pyinfra/api/config.py +27 -22
- pyinfra/api/connect.py +1 -1
- pyinfra/api/connectors.py +2 -24
- pyinfra/api/deploy.py +21 -52
- pyinfra/api/exceptions.py +33 -8
- pyinfra/api/facts.py +77 -113
- pyinfra/api/host.py +150 -82
- pyinfra/api/inventory.py +17 -25
- pyinfra/api/operation.py +232 -198
- pyinfra/api/operations.py +102 -148
- pyinfra/api/state.py +137 -79
- pyinfra/api/util.py +55 -70
- pyinfra/connectors/base.py +150 -0
- pyinfra/connectors/chroot.py +160 -169
- pyinfra/connectors/docker.py +227 -237
- pyinfra/connectors/dockerssh.py +231 -253
- pyinfra/connectors/local.py +195 -207
- pyinfra/connectors/ssh.py +528 -615
- pyinfra/connectors/ssh_util.py +114 -0
- pyinfra/connectors/sshuserclient/client.py +5 -3
- pyinfra/connectors/terraform.py +86 -65
- pyinfra/connectors/util.py +212 -137
- pyinfra/connectors/vagrant.py +55 -48
- pyinfra/context.py +3 -2
- pyinfra/facts/docker.py +1 -0
- pyinfra/facts/files.py +45 -32
- pyinfra/facts/git.py +3 -1
- pyinfra/facts/gpg.py +1 -1
- pyinfra/facts/hardware.py +4 -2
- pyinfra/facts/iptables.py +5 -3
- pyinfra/facts/mysql.py +1 -0
- pyinfra/facts/postgres.py +168 -0
- pyinfra/facts/postgresql.py +5 -161
- pyinfra/facts/selinux.py +3 -1
- pyinfra/facts/server.py +77 -30
- pyinfra/facts/systemd.py +29 -12
- pyinfra/facts/sysvinit.py +10 -10
- pyinfra/facts/util/packaging.py +4 -2
- pyinfra/local.py +4 -5
- pyinfra/operations/apk.py +3 -3
- pyinfra/operations/apt.py +25 -47
- pyinfra/operations/brew.py +7 -14
- pyinfra/operations/bsdinit.py +4 -4
- pyinfra/operations/cargo.py +1 -1
- pyinfra/operations/choco.py +1 -1
- pyinfra/operations/dnf.py +4 -4
- pyinfra/operations/files.py +108 -321
- pyinfra/operations/gem.py +1 -1
- pyinfra/operations/git.py +6 -37
- pyinfra/operations/iptables.py +2 -10
- pyinfra/operations/launchd.py +1 -1
- pyinfra/operations/lxd.py +1 -9
- pyinfra/operations/mysql.py +5 -28
- pyinfra/operations/npm.py +1 -1
- pyinfra/operations/openrc.py +1 -1
- pyinfra/operations/pacman.py +3 -3
- pyinfra/operations/pip.py +14 -15
- pyinfra/operations/pkg.py +1 -1
- pyinfra/operations/pkgin.py +3 -3
- pyinfra/operations/postgres.py +347 -0
- pyinfra/operations/postgresql.py +17 -380
- pyinfra/operations/python.py +2 -17
- pyinfra/operations/selinux.py +5 -28
- pyinfra/operations/server.py +59 -84
- pyinfra/operations/snap.py +1 -3
- pyinfra/operations/ssh.py +8 -23
- pyinfra/operations/systemd.py +7 -7
- pyinfra/operations/sysvinit.py +3 -12
- pyinfra/operations/upstart.py +4 -4
- pyinfra/operations/util/__init__.py +12 -0
- pyinfra/operations/util/files.py +2 -2
- pyinfra/operations/util/packaging.py +6 -24
- pyinfra/operations/util/service.py +18 -37
- pyinfra/operations/vzctl.py +2 -2
- pyinfra/operations/xbps.py +3 -3
- pyinfra/operations/yum.py +4 -4
- pyinfra/operations/zypper.py +4 -4
- {pyinfra-2.9.2.dist-info → pyinfra-3.0b1.dist-info}/METADATA +19 -22
- pyinfra-3.0b1.dist-info/RECORD +163 -0
- pyinfra-3.0b1.dist-info/entry_points.txt +11 -0
- pyinfra_cli/__main__.py +2 -0
- pyinfra_cli/commands.py +7 -2
- pyinfra_cli/exceptions.py +83 -42
- pyinfra_cli/inventory.py +19 -4
- pyinfra_cli/log.py +17 -3
- pyinfra_cli/main.py +133 -90
- pyinfra_cli/prints.py +93 -129
- pyinfra_cli/util.py +60 -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 +100 -200
- 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 +66 -107
- tests/test_connectors/test_terraform.py +9 -15
- tests/test_connectors/test_util.py +24 -46
- tests/test_connectors/test_vagrant.py +4 -4
- 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.2.dist-info/RECORD +0 -170
- pyinfra-2.9.2.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.2.dist-info → pyinfra-3.0b1.dist-info}/LICENSE.md +0 -0
- {pyinfra-2.9.2.dist-info → pyinfra-3.0b1.dist-info}/WHEEL +0 -0
- {pyinfra-2.9.2.dist-info → pyinfra-3.0b1.dist-info}/top_level.txt +0 -0
pyinfra/api/facts.py
CHANGED
|
@@ -8,10 +8,23 @@ it's possible to call facts on hosts out of context (ie give me the IP of this
|
|
|
8
8
|
other host B while I operate on this host A).
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
11
13
|
import re
|
|
12
14
|
from inspect import getcallargs
|
|
13
15
|
from socket import error as socket_error, timeout as timeout_error
|
|
14
|
-
from typing import
|
|
16
|
+
from typing import (
|
|
17
|
+
TYPE_CHECKING,
|
|
18
|
+
Any,
|
|
19
|
+
Callable,
|
|
20
|
+
Generic,
|
|
21
|
+
Iterable,
|
|
22
|
+
Optional,
|
|
23
|
+
Type,
|
|
24
|
+
TypeVar,
|
|
25
|
+
Union,
|
|
26
|
+
cast,
|
|
27
|
+
)
|
|
15
28
|
|
|
16
29
|
import click
|
|
17
30
|
import gevent
|
|
@@ -27,11 +40,11 @@ from pyinfra.api.util import (
|
|
|
27
40
|
make_hash,
|
|
28
41
|
print_host_combined_output,
|
|
29
42
|
)
|
|
30
|
-
from pyinfra.connectors.util import
|
|
43
|
+
from pyinfra.connectors.util import CommandOutput
|
|
31
44
|
from pyinfra.context import ctx_host, ctx_state
|
|
32
45
|
from pyinfra.progress import progress_spinner
|
|
33
46
|
|
|
34
|
-
from .arguments import
|
|
47
|
+
from .arguments import CONNECTOR_ARGUMENT_KEYS
|
|
35
48
|
|
|
36
49
|
if TYPE_CHECKING:
|
|
37
50
|
from pyinfra.api.host import Host
|
|
@@ -44,14 +57,10 @@ SU_REGEXES = (
|
|
|
44
57
|
)
|
|
45
58
|
|
|
46
59
|
|
|
47
|
-
|
|
48
|
-
def __init__(cls, name: str, bases, attrs, **kwargs):
|
|
49
|
-
super().__init__(name, bases, attrs, **kwargs)
|
|
50
|
-
module_name = cls.__module__.replace("pyinfra.facts.", "")
|
|
51
|
-
cls.name = f"{module_name}.{cls.__name__}"
|
|
60
|
+
T = TypeVar("T")
|
|
52
61
|
|
|
53
62
|
|
|
54
|
-
class FactBase(
|
|
63
|
+
class FactBase(Generic[T]):
|
|
55
64
|
name: str
|
|
56
65
|
|
|
57
66
|
abstract: bool = True
|
|
@@ -62,23 +71,36 @@ class FactBase(metaclass=FactNameMeta):
|
|
|
62
71
|
|
|
63
72
|
command: Union[str, Callable]
|
|
64
73
|
|
|
74
|
+
def __init_subclass__(cls) -> None:
|
|
75
|
+
super().__init_subclass__()
|
|
76
|
+
module_name = cls.__module__.replace("pyinfra.facts.", "")
|
|
77
|
+
cls.name = f"{module_name}.{cls.__name__}"
|
|
78
|
+
|
|
65
79
|
@staticmethod
|
|
66
|
-
def default():
|
|
80
|
+
def default() -> T:
|
|
67
81
|
"""
|
|
68
82
|
Set the default attribute to be a type (eg list/dict).
|
|
69
83
|
"""
|
|
70
84
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
85
|
+
return cast(T, None)
|
|
86
|
+
|
|
87
|
+
def process(self, output: Iterable[str]) -> T:
|
|
88
|
+
# NOTE: TypeVar does not support a default, so we have to cast this str -> T
|
|
89
|
+
return cast(T, "\n".join(output))
|
|
74
90
|
|
|
75
91
|
def process_pipeline(self, args, output):
|
|
76
92
|
return {arg: self.process([output[i]]) for i, arg in enumerate(args)}
|
|
77
93
|
|
|
78
94
|
|
|
79
|
-
class ShortFactBase(
|
|
95
|
+
class ShortFactBase(Generic[T]):
|
|
96
|
+
name: str
|
|
80
97
|
fact: Type[FactBase]
|
|
81
98
|
|
|
99
|
+
def __init_subclass__(cls) -> None:
|
|
100
|
+
super().__init_subclass__()
|
|
101
|
+
module_name = cls.__module__.replace("pyinfra.facts.", "")
|
|
102
|
+
cls.name = f"{module_name}.{cls.__name__}"
|
|
103
|
+
|
|
82
104
|
@staticmethod
|
|
83
105
|
def process_data(data):
|
|
84
106
|
return data
|
|
@@ -99,8 +121,8 @@ def _make_command(command_attribute, host_args):
|
|
|
99
121
|
def _get_executor_kwargs(
|
|
100
122
|
state: "State",
|
|
101
123
|
host: "Host",
|
|
102
|
-
override_kwargs: Optional[
|
|
103
|
-
override_kwarg_keys: Optional[
|
|
124
|
+
override_kwargs: Optional[dict[str, Any]] = None,
|
|
125
|
+
override_kwarg_keys: Optional[list[str]] = None,
|
|
104
126
|
):
|
|
105
127
|
if override_kwargs is None:
|
|
106
128
|
override_kwargs = {}
|
|
@@ -108,7 +130,7 @@ def _get_executor_kwargs(
|
|
|
108
130
|
override_kwarg_keys = []
|
|
109
131
|
|
|
110
132
|
# Use the current operation global kwargs, or generate defaults
|
|
111
|
-
global_kwargs = host.
|
|
133
|
+
global_kwargs = host.current_op_global_arguments
|
|
112
134
|
if not global_kwargs:
|
|
113
135
|
global_kwargs, _ = pop_global_arguments({}, state, host)
|
|
114
136
|
|
|
@@ -117,9 +139,7 @@ def _get_executor_kwargs(
|
|
|
117
139
|
{key: value for key, value in global_kwargs.items() if key not in override_kwarg_keys},
|
|
118
140
|
)
|
|
119
141
|
|
|
120
|
-
return {
|
|
121
|
-
key: value for key, value in override_kwargs.items() if key in get_executor_kwarg_keys()
|
|
122
|
-
}
|
|
142
|
+
return {key: value for key, value in override_kwargs.items() if key in CONNECTOR_ARGUMENT_KEYS}
|
|
123
143
|
|
|
124
144
|
|
|
125
145
|
def _handle_fact_kwargs(state, host, cls, args, kwargs):
|
|
@@ -136,13 +156,13 @@ def _handle_fact_kwargs(state, host, cls, args, kwargs):
|
|
|
136
156
|
kwargs,
|
|
137
157
|
state=state,
|
|
138
158
|
host=host,
|
|
139
|
-
keys_to_check=
|
|
159
|
+
keys_to_check=CONNECTOR_ARGUMENT_KEYS,
|
|
140
160
|
)
|
|
141
161
|
|
|
142
162
|
executor_kwargs = _get_executor_kwargs(
|
|
143
163
|
state,
|
|
144
164
|
host,
|
|
145
|
-
override_kwargs=override_kwargs,
|
|
165
|
+
override_kwargs=override_kwargs, # type: ignore[arg-type]
|
|
146
166
|
override_kwarg_keys=override_kwarg_keys,
|
|
147
167
|
)
|
|
148
168
|
|
|
@@ -181,14 +201,12 @@ def get_facts(state: "State", *args, **kwargs):
|
|
|
181
201
|
def get_fact(
|
|
182
202
|
state: "State",
|
|
183
203
|
host: "Host",
|
|
184
|
-
cls:
|
|
204
|
+
cls: type[FactBase],
|
|
185
205
|
args: Optional[Any] = None,
|
|
186
206
|
kwargs: Optional[Any] = None,
|
|
187
207
|
ensure_hosts: Optional[Any] = None,
|
|
188
208
|
apply_failed_hosts: bool = True,
|
|
189
|
-
|
|
190
|
-
use_cache: bool = True,
|
|
191
|
-
):
|
|
209
|
+
) -> Any:
|
|
192
210
|
if issubclass(cls, ShortFactBase):
|
|
193
211
|
return get_short_facts(
|
|
194
212
|
state,
|
|
@@ -198,36 +216,28 @@ def get_fact(
|
|
|
198
216
|
kwargs=kwargs,
|
|
199
217
|
ensure_hosts=ensure_hosts,
|
|
200
218
|
apply_failed_hosts=apply_failed_hosts,
|
|
201
|
-
fact_hash=fact_hash,
|
|
202
|
-
use_cache=use_cache,
|
|
203
219
|
)
|
|
204
220
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
kwargs,
|
|
215
|
-
ensure_hosts,
|
|
216
|
-
apply_failed_hosts,
|
|
217
|
-
fact_hash,
|
|
218
|
-
)
|
|
221
|
+
return _get_fact(
|
|
222
|
+
state,
|
|
223
|
+
host,
|
|
224
|
+
cls,
|
|
225
|
+
args,
|
|
226
|
+
kwargs,
|
|
227
|
+
ensure_hosts,
|
|
228
|
+
apply_failed_hosts,
|
|
229
|
+
)
|
|
219
230
|
|
|
220
231
|
|
|
221
232
|
def _get_fact(
|
|
222
233
|
state: "State",
|
|
223
234
|
host: "Host",
|
|
224
|
-
cls:
|
|
225
|
-
args: Optional[
|
|
226
|
-
kwargs: Optional[
|
|
235
|
+
cls: type[FactBase],
|
|
236
|
+
args: Optional[list] = None,
|
|
237
|
+
kwargs: Optional[dict] = None,
|
|
227
238
|
ensure_hosts: Optional[Any] = None,
|
|
228
239
|
apply_failed_hosts: bool = True,
|
|
229
|
-
|
|
230
|
-
):
|
|
240
|
+
) -> Any:
|
|
231
241
|
fact = cls()
|
|
232
242
|
name = fact.name
|
|
233
243
|
|
|
@@ -247,14 +257,15 @@ def _get_fact(
|
|
|
247
257
|
raise_exceptions=True,
|
|
248
258
|
)
|
|
249
259
|
|
|
250
|
-
ignore_errors = (
|
|
251
|
-
"
|
|
252
|
-
|
|
260
|
+
ignore_errors = (
|
|
261
|
+
host.current_op_global_arguments["_ignore_errors"]
|
|
262
|
+
if host.in_op and host.current_op_global_arguments
|
|
263
|
+
else state.config.IGNORE_ERRORS
|
|
253
264
|
)
|
|
254
265
|
|
|
255
266
|
# Facts can override the shell (winrm powershell vs cmd support)
|
|
256
267
|
if fact.shell_executable:
|
|
257
|
-
executor_kwargs["
|
|
268
|
+
executor_kwargs["_shell_executable"] = fact.shell_executable
|
|
258
269
|
|
|
259
270
|
command = _make_command(fact.command, fact_kwargs)
|
|
260
271
|
requires_command = _make_command(fact.requires_command, fact_kwargs)
|
|
@@ -271,40 +282,38 @@ def _get_fact(
|
|
|
271
282
|
)
|
|
272
283
|
|
|
273
284
|
status = False
|
|
274
|
-
|
|
275
|
-
combined_output_lines = []
|
|
285
|
+
output = CommandOutput([])
|
|
276
286
|
|
|
277
287
|
try:
|
|
278
|
-
status,
|
|
288
|
+
status, output = host.run_shell_command(
|
|
279
289
|
command,
|
|
280
290
|
print_output=state.print_fact_output,
|
|
281
291
|
print_input=state.print_fact_input,
|
|
282
|
-
return_combined_output=True,
|
|
283
292
|
**executor_kwargs,
|
|
284
293
|
)
|
|
285
294
|
except (timeout_error, socket_error, SSHException) as e:
|
|
286
295
|
log_host_command_error(
|
|
287
296
|
host,
|
|
288
297
|
e,
|
|
289
|
-
timeout=executor_kwargs["
|
|
298
|
+
timeout=executor_kwargs["_timeout"],
|
|
290
299
|
)
|
|
291
300
|
|
|
292
|
-
|
|
301
|
+
stdout_lines, stderr_lines = output.stdout_lines, output.stderr_lines
|
|
293
302
|
|
|
294
303
|
data = fact.default()
|
|
295
304
|
|
|
296
305
|
if status:
|
|
297
|
-
if
|
|
298
|
-
data = fact.process(
|
|
299
|
-
elif
|
|
306
|
+
if stdout_lines:
|
|
307
|
+
data = fact.process(stdout_lines)
|
|
308
|
+
elif stderr_lines:
|
|
300
309
|
# If we have error output and that error is sudo or su stating the user
|
|
301
310
|
# does not exist, do not fail but instead return the default fact value.
|
|
302
311
|
# This allows for users that don't currently but may be created during
|
|
303
312
|
# other operations.
|
|
304
|
-
first_line =
|
|
305
|
-
if executor_kwargs["
|
|
313
|
+
first_line = stderr_lines[0]
|
|
314
|
+
if executor_kwargs["_sudo_user"] and re.match(SUDO_REGEX, first_line):
|
|
306
315
|
status = True
|
|
307
|
-
if executor_kwargs["
|
|
316
|
+
if executor_kwargs["_su_user"] and any(re.match(regex, first_line) for regex in SU_REGEXES):
|
|
308
317
|
status = True
|
|
309
318
|
|
|
310
319
|
if status:
|
|
@@ -321,7 +330,7 @@ def _get_fact(
|
|
|
321
330
|
logger.debug(log_message)
|
|
322
331
|
else:
|
|
323
332
|
if not state.print_fact_output:
|
|
324
|
-
print_host_combined_output(host,
|
|
333
|
+
print_host_combined_output(host, output)
|
|
325
334
|
|
|
326
335
|
log_error_or_warning(
|
|
327
336
|
host,
|
|
@@ -333,8 +342,6 @@ def _get_fact(
|
|
|
333
342
|
if not status and not ignore_errors and apply_failed_hosts:
|
|
334
343
|
state.fail_hosts({host})
|
|
335
344
|
|
|
336
|
-
if fact_hash:
|
|
337
|
-
host.facts[fact_hash] = data
|
|
338
345
|
return data
|
|
339
346
|
|
|
340
347
|
|
|
@@ -349,50 +356,7 @@ def get_host_fact(
|
|
|
349
356
|
state: "State",
|
|
350
357
|
host: "Host",
|
|
351
358
|
cls,
|
|
352
|
-
args: Optional[
|
|
353
|
-
kwargs: Optional[
|
|
354
|
-
):
|
|
355
|
-
|
|
356
|
-
return get_fact(state, host, cls, args=args, kwargs=kwargs, fact_hash=fact_hash)
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
def reload_host_fact(
|
|
360
|
-
state: "State",
|
|
361
|
-
host: "Host",
|
|
362
|
-
cls,
|
|
363
|
-
args: Optional[List] = None,
|
|
364
|
-
kwargs: Optional[Dict] = None,
|
|
365
|
-
):
|
|
366
|
-
fact_hash = _get_fact_hash(state, host, cls, args, kwargs)
|
|
367
|
-
return get_fact(
|
|
368
|
-
state,
|
|
369
|
-
host,
|
|
370
|
-
cls,
|
|
371
|
-
args=args,
|
|
372
|
-
kwargs=kwargs,
|
|
373
|
-
fact_hash=fact_hash,
|
|
374
|
-
use_cache=False,
|
|
375
|
-
)
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
def create_host_fact(
|
|
379
|
-
state: "State",
|
|
380
|
-
host: "Host",
|
|
381
|
-
cls,
|
|
382
|
-
data,
|
|
383
|
-
args: Optional[List] = None,
|
|
384
|
-
kwargs: Optional[Dict] = None,
|
|
385
|
-
):
|
|
386
|
-
fact_hash = _get_fact_hash(state, host, cls, args, kwargs)
|
|
387
|
-
host.facts[fact_hash] = data
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
def delete_host_fact(
|
|
391
|
-
state: "State",
|
|
392
|
-
host: "Host",
|
|
393
|
-
cls,
|
|
394
|
-
args: Optional[List] = None,
|
|
395
|
-
kwargs: Optional[Dict] = None,
|
|
396
|
-
):
|
|
397
|
-
fact_hash = _get_fact_hash(state, host, cls, args, kwargs)
|
|
398
|
-
host.facts.pop(fact_hash, None)
|
|
359
|
+
args: Optional[Iterable] = None,
|
|
360
|
+
kwargs: Optional[dict] = None,
|
|
361
|
+
) -> Any:
|
|
362
|
+
return get_fact(state, host, cls, args=args, kwargs=kwargs)
|