pyinfra 3.0b0__tar.gz → 3.0b1__tar.gz
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-3.0b0 → pyinfra-3.0b1}/CHANGELOG.md +1 -1
- {pyinfra-3.0b0/pyinfra.egg-info → pyinfra-3.0b1}/PKG-INFO +6 -6
- {pyinfra-3.0b0 → pyinfra-3.0b1}/README.md +5 -5
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/__init__.py +3 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/arguments.py +5 -4
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/arguments_typed.py +12 -2
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/exceptions.py +19 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/facts.py +1 -1
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/host.py +46 -7
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/operation.py +77 -39
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/operations.py +10 -11
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/state.py +11 -2
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/connectors/base.py +1 -1
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/connectors/chroot.py +5 -6
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/connectors/docker.py +11 -10
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/connectors/dockerssh.py +5 -4
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/connectors/local.py +5 -5
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/connectors/ssh.py +44 -23
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/connectors/terraform.py +9 -6
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/connectors/util.py +1 -1
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/connectors/vagrant.py +6 -5
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/choco.py +1 -1
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/deb.py +2 -2
- pyinfra-3.0b0/pyinfra/facts/postgresql.py → pyinfra-3.0b1/pyinfra/facts/postgres.py +3 -3
- pyinfra-3.0b1/pyinfra/facts/postgresql.py +9 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/systemd.py +26 -10
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/files.py +5 -3
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/iptables.py +6 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/pip.py +5 -0
- pyinfra-3.0b0/pyinfra/operations/postgresql.py → pyinfra-3.0b1/pyinfra/operations/postgres.py +5 -5
- pyinfra-3.0b1/pyinfra/operations/postgresql.py +28 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/systemd.py +5 -3
- {pyinfra-3.0b0 → pyinfra-3.0b1/pyinfra.egg-info}/PKG-INFO +6 -6
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra.egg-info/SOURCES.txt +2 -1
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra_cli/commands.py +3 -2
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra_cli/exceptions.py +5 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra_cli/main.py +2 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra_cli/prints.py +22 -104
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_api/test_api_deploys.py +5 -5
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_api/test_api_operations.py +4 -4
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_connectors/test_ssh.py +52 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_connectors/test_terraform.py +11 -8
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_connectors/test_vagrant.py +3 -3
- pyinfra-3.0b0/pyinfra_cli/inventory_dsl.py +0 -23
- {pyinfra-3.0b0 → pyinfra-3.0b1}/LICENSE.md +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/MANIFEST.in +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/__init__.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/__main__.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/command.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/config.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/connect.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/connectors.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/deploy.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/inventory.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/api/util.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/connectors/__init__.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/connectors/ssh_util.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/connectors/sshuserclient/__init__.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/connectors/sshuserclient/client.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/connectors/sshuserclient/config.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/context.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/__init__.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/apk.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/apt.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/brew.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/bsdinit.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/cargo.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/dnf.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/docker.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/files.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/gem.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/git.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/gpg.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/hardware.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/iptables.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/launchd.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/lxd.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/mysql.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/npm.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/openrc.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/pacman.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/pip.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/pkg.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/pkgin.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/rpm.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/selinux.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/server.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/snap.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/sysvinit.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/upstart.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/util/__init__.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/util/databases.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/util/packaging.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/util/win_files.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/vzctl.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/xbps.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/yum.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/facts/zypper.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/local.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/__init__.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/apk.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/apt.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/brew.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/bsdinit.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/cargo.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/choco.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/dnf.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/gem.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/git.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/launchd.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/lxd.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/mysql.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/npm.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/openrc.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/pacman.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/pkg.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/pkgin.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/puppet.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/python.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/selinux.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/server.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/snap.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/ssh.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/sysvinit.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/upstart.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/util/__init__.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/util/files.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/util/packaging.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/util/service.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/vzctl.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/xbps.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/yum.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/operations/zypper.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/progress.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/py.typed +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra/version.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra.egg-info/dependency_links.txt +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra.egg-info/entry_points.txt +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra.egg-info/requires.txt +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra.egg-info/top_level.txt +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra_cli/__init__.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra_cli/__main__.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra_cli/inventory.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra_cli/log.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra_cli/util.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyinfra_cli/virtualenv.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/pyproject.toml +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/setup.cfg +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/setup.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/__init__.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/paramiko_util.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_api/__init__.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_api/test_api.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_api/test_api_arguments.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_api/test_api_command.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_api/test_api_config.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_api/test_api_facts.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_api/test_api_host.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_api/test_api_inventory.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_api/test_api_util.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_cli/__init__.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_cli/test_cli.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_cli/test_cli_deploy.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_cli/test_cli_exceptions.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_cli/test_cli_util.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_cli/test_context_objects.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_cli/util.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_connectors/__init__.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_connectors/test_chroot.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_connectors/test_docker.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_connectors/test_dockerssh.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_connectors/test_local.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_connectors/test_sshuserclient.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_connectors/test_util.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_facts.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_global_arguments.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_operations.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/test_operations_utils.py +0 -0
- {pyinfra-3.0b0 → pyinfra-3.0b1}/tests/util.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyinfra
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.0b1
|
|
4
4
|
Summary: pyinfra automates/provisions/manages/deploys infrastructure.
|
|
5
5
|
Home-page: https://pyinfra.com
|
|
6
6
|
Author: Nick / Fizzadar
|
|
@@ -35,17 +35,17 @@ License-File: LICENSE.md
|
|
|
35
35
|
</a>
|
|
36
36
|
</p>
|
|
37
37
|
|
|
38
|
-
<p
|
|
38
|
+
<p>
|
|
39
39
|
<strong>Note: this is the v3 branch, which is currently in beta. <a href="https://docs.pyinfra.com/en/next">See the docs for v3</a>. If needed the <a href="https://github.com/pyinfra-dev/pyinfra/tree/2.x/">2.x branch is here</a>, but is in bugfix only mode.</strong>
|
|
40
40
|
</p>
|
|
41
41
|
|
|
42
|
-
<p
|
|
43
|
-
|
|
42
|
+
<p>
|
|
43
|
+
pyinfra turns Python code into shell commands and runs them on your servers. Execute ad-hoc commands and write declarative operations. Target SSH servers, local machine and Docker containers. Fast and scales from one server to thousands. Think <code>ansible</code> but Python instead of YAML, and a lot faster.
|
|
44
44
|
</p>
|
|
45
45
|
|
|
46
46
|
---
|
|
47
47
|
|
|
48
|
-
<p
|
|
48
|
+
<p>
|
|
49
49
|
<a href="https://docs.pyinfra.com"><strong>Documentation</strong></a> ⇒
|
|
50
50
|
<a href="https://docs.pyinfra.com/page/getting-started.html"><strong>Getting Started</strong></a> •
|
|
51
51
|
<a href="https://docs.pyinfra.com/page/examples.html"><strong>Examples</strong></a> •
|
|
@@ -53,7 +53,7 @@ License-File: LICENSE.md
|
|
|
53
53
|
<a href="https://docs.pyinfra.com/page/contributing.html"><strong>Contributing</strong></a>
|
|
54
54
|
</p>
|
|
55
55
|
|
|
56
|
-
<p
|
|
56
|
+
<p>
|
|
57
57
|
Chat ⇒
|
|
58
58
|
<a href="https://matrix.to/#/#pyinfra:matrix.org"><strong><code>#pyinfra</code> on Matrix</strong></a>
|
|
59
59
|
</p>
|
|
@@ -4,17 +4,17 @@
|
|
|
4
4
|
</a>
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
-
<p
|
|
7
|
+
<p>
|
|
8
8
|
<strong>Note: this is the v3 branch, which is currently in beta. <a href="https://docs.pyinfra.com/en/next">See the docs for v3</a>. If needed the <a href="https://github.com/pyinfra-dev/pyinfra/tree/2.x/">2.x branch is here</a>, but is in bugfix only mode.</strong>
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
|
-
<p
|
|
12
|
-
|
|
11
|
+
<p>
|
|
12
|
+
pyinfra turns Python code into shell commands and runs them on your servers. Execute ad-hoc commands and write declarative operations. Target SSH servers, local machine and Docker containers. Fast and scales from one server to thousands. Think <code>ansible</code> but Python instead of YAML, and a lot faster.
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
-
<p
|
|
17
|
+
<p>
|
|
18
18
|
<a href="https://docs.pyinfra.com"><strong>Documentation</strong></a> ⇒
|
|
19
19
|
<a href="https://docs.pyinfra.com/page/getting-started.html"><strong>Getting Started</strong></a> •
|
|
20
20
|
<a href="https://docs.pyinfra.com/page/examples.html"><strong>Examples</strong></a> •
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
<a href="https://docs.pyinfra.com/page/contributing.html"><strong>Contributing</strong></a>
|
|
23
23
|
</p>
|
|
24
24
|
|
|
25
|
-
<p
|
|
25
|
+
<p>
|
|
26
26
|
Chat ⇒
|
|
27
27
|
<a href="https://matrix.to/#/#pyinfra:matrix.org"><strong><code>#pyinfra</code> on Matrix</strong></a>
|
|
28
28
|
</p>
|
|
@@ -11,6 +11,9 @@ from .config import Config # noqa: F401 # pragma: no cover
|
|
|
11
11
|
from .deploy import deploy # noqa: F401 # pragma: no cover
|
|
12
12
|
from .exceptions import DeployError # noqa: F401 # pragma: no cover
|
|
13
13
|
from .exceptions import ( # noqa: F401
|
|
14
|
+
FactError,
|
|
15
|
+
FactTypeError,
|
|
16
|
+
FactValueError,
|
|
14
17
|
InventoryError,
|
|
15
18
|
OperationError,
|
|
16
19
|
OperationTypeError,
|
|
@@ -6,6 +6,7 @@ from typing import (
|
|
|
6
6
|
Callable,
|
|
7
7
|
Generic,
|
|
8
8
|
Iterable,
|
|
9
|
+
List,
|
|
9
10
|
Mapping,
|
|
10
11
|
Optional,
|
|
11
12
|
TypeVar,
|
|
@@ -169,7 +170,7 @@ class MetaArguments(TypedDict):
|
|
|
169
170
|
name: str
|
|
170
171
|
_ignore_errors: bool
|
|
171
172
|
_continue_on_error: bool
|
|
172
|
-
_if: Callable[[], bool]
|
|
173
|
+
_if: List[Callable[[], bool]]
|
|
173
174
|
|
|
174
175
|
|
|
175
176
|
meta_argument_meta: dict[str, ArgumentMeta] = {
|
|
@@ -190,8 +191,8 @@ meta_argument_meta: dict[str, ArgumentMeta] = {
|
|
|
190
191
|
default=lambda _: False,
|
|
191
192
|
),
|
|
192
193
|
"_if": ArgumentMeta(
|
|
193
|
-
"Only run this operation if
|
|
194
|
-
default=lambda _:
|
|
194
|
+
"Only run this operation if these functions returns True",
|
|
195
|
+
default=lambda _: [],
|
|
195
196
|
),
|
|
196
197
|
}
|
|
197
198
|
|
|
@@ -299,7 +300,7 @@ def pop_global_arguments(
|
|
|
299
300
|
if context.ctx_config.isset():
|
|
300
301
|
config = context.config
|
|
301
302
|
|
|
302
|
-
meta_kwargs = host.current_deploy_kwargs or {}
|
|
303
|
+
meta_kwargs: dict[str, Any] = host.current_deploy_kwargs or {} # type: ignore[assignment]
|
|
303
304
|
|
|
304
305
|
arguments: dict[str, Any] = {}
|
|
305
306
|
found_keys: list[str] = []
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import (
|
|
4
|
+
TYPE_CHECKING,
|
|
5
|
+
Callable,
|
|
6
|
+
Generator,
|
|
7
|
+
Generic,
|
|
8
|
+
Iterable,
|
|
9
|
+
List,
|
|
10
|
+
Mapping,
|
|
11
|
+
Optional,
|
|
12
|
+
Union,
|
|
13
|
+
)
|
|
4
14
|
|
|
5
15
|
from typing_extensions import ParamSpec, Protocol
|
|
6
16
|
|
|
@@ -51,7 +61,7 @@ class PyinfraOperation(Generic[P], Protocol):
|
|
|
51
61
|
name: Optional[str] = None,
|
|
52
62
|
_ignore_errors: bool = False,
|
|
53
63
|
_continue_on_error: bool = False,
|
|
54
|
-
_if: Optional[Callable[[], bool]] = None,
|
|
64
|
+
_if: Optional[List[Callable[[], bool]]] = None,
|
|
55
65
|
#
|
|
56
66
|
# ExecutionArguments
|
|
57
67
|
#
|
|
@@ -10,6 +10,25 @@ class ConnectError(PyinfraError):
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
class FactError(PyinfraError):
|
|
14
|
+
"""
|
|
15
|
+
Exception raised during fact gathering staging if a fact is unable to
|
|
16
|
+
generate output/change state.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class FactTypeError(FactError, TypeError):
|
|
21
|
+
"""
|
|
22
|
+
Exception raised when a fact is passed invalid argument types.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class FactValueError(FactError, ValueError):
|
|
27
|
+
"""
|
|
28
|
+
Exception raised when a fact is passed invalid argument values.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
|
|
13
32
|
class OperationError(PyinfraError):
|
|
14
33
|
"""
|
|
15
34
|
Exception raised during fact gathering staging if an operation is unable to
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from contextlib import contextmanager
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import (
|
|
5
|
+
TYPE_CHECKING,
|
|
6
|
+
Any,
|
|
7
|
+
Callable,
|
|
8
|
+
Generator,
|
|
9
|
+
Optional,
|
|
10
|
+
Type,
|
|
11
|
+
TypeVar,
|
|
12
|
+
Union,
|
|
13
|
+
cast,
|
|
14
|
+
overload,
|
|
15
|
+
)
|
|
5
16
|
from uuid import uuid4
|
|
6
17
|
|
|
7
18
|
import click
|
|
19
|
+
from typing_extensions import Unpack
|
|
8
20
|
|
|
9
21
|
from pyinfra import logger
|
|
10
22
|
from pyinfra.connectors.base import BaseConnector
|
|
@@ -98,11 +110,16 @@ class Host:
|
|
|
98
110
|
current_op_hash: Optional[str] = None
|
|
99
111
|
current_op_global_arguments: Optional["AllArguments"] = None
|
|
100
112
|
|
|
101
|
-
# Current context inside a @deploy function
|
|
113
|
+
# Current context inside a @deploy function which become part of the op data
|
|
102
114
|
in_deploy: bool = False
|
|
103
115
|
current_deploy_name: Optional[str] = None
|
|
104
116
|
current_deploy_kwargs = None
|
|
105
|
-
|
|
117
|
+
|
|
118
|
+
# @deploy decorator data is a bit different - we need to handle the case
|
|
119
|
+
# where we're evaluating an operation at runtime (current_op_) but also
|
|
120
|
+
# when ordering operations (current_) outside of an operation context.
|
|
121
|
+
current_op_deploy_data: Optional[dict[str, Any]] = None
|
|
122
|
+
current_deploy_data: Optional[dict[str, Any]] = None
|
|
106
123
|
|
|
107
124
|
# Current context during operation execution
|
|
108
125
|
executing_op_hash: Optional[str] = None
|
|
@@ -204,9 +221,7 @@ class Host:
|
|
|
204
221
|
self.log(message_styled, log_func=log_func)
|
|
205
222
|
|
|
206
223
|
def get_deploy_data(self):
|
|
207
|
-
|
|
208
|
-
return self.current_deploy_data
|
|
209
|
-
return {}
|
|
224
|
+
return self.current_op_deploy_data or self.current_deploy_data or {}
|
|
210
225
|
|
|
211
226
|
def noop(self, description):
|
|
212
227
|
"""
|
|
@@ -216,8 +231,25 @@ class Host:
|
|
|
216
231
|
handler = logger.info if self.state.print_noop_info else logger.debug
|
|
217
232
|
handler("{0}noop: {1}".format(self.print_prefix, description))
|
|
218
233
|
|
|
234
|
+
def when(self, condition: Callable[[], bool]):
|
|
235
|
+
return self.deploy(
|
|
236
|
+
"",
|
|
237
|
+
cast("AllArguments", {"_if": [condition]}),
|
|
238
|
+
{},
|
|
239
|
+
in_deploy=False,
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
def arguments(self, **arguments: Unpack["AllArguments"]):
|
|
243
|
+
return self.deploy("", arguments, {}, in_deploy=False)
|
|
244
|
+
|
|
219
245
|
@contextmanager
|
|
220
|
-
def deploy(
|
|
246
|
+
def deploy(
|
|
247
|
+
self,
|
|
248
|
+
name: str,
|
|
249
|
+
kwargs: Optional["AllArguments"],
|
|
250
|
+
data: Optional[dict],
|
|
251
|
+
in_deploy: bool = True,
|
|
252
|
+
):
|
|
221
253
|
"""
|
|
222
254
|
Wraps a group of operations as a deploy, this should not be used
|
|
223
255
|
directly, instead use ``pyinfra.api.deploy.deploy``.
|
|
@@ -234,6 +266,13 @@ class Host:
|
|
|
234
266
|
old_deploy_data = self.current_deploy_data
|
|
235
267
|
self.in_deploy = in_deploy
|
|
236
268
|
|
|
269
|
+
# Combine any old _ifs with the new ones
|
|
270
|
+
if old_deploy_kwargs and kwargs:
|
|
271
|
+
old_ifs = old_deploy_kwargs["_if"]
|
|
272
|
+
new_ifs = kwargs["_if"]
|
|
273
|
+
if old_ifs and new_ifs:
|
|
274
|
+
kwargs["_if"] = old_ifs + new_ifs
|
|
275
|
+
|
|
237
276
|
# Set the new values
|
|
238
277
|
self.current_deploy_name = name
|
|
239
278
|
self.current_deploy_kwargs = kwargs
|
|
@@ -11,7 +11,7 @@ from functools import wraps
|
|
|
11
11
|
from inspect import signature
|
|
12
12
|
from io import StringIO
|
|
13
13
|
from types import FunctionType
|
|
14
|
-
from typing import Any, Callable, Generator, Iterator, Optional, cast
|
|
14
|
+
from typing import TYPE_CHECKING, Any, Callable, Generator, Iterator, Optional, cast
|
|
15
15
|
|
|
16
16
|
from typing_extensions import ParamSpec
|
|
17
17
|
|
|
@@ -36,16 +36,19 @@ from .util import (
|
|
|
36
36
|
|
|
37
37
|
op_meta_default = object()
|
|
38
38
|
|
|
39
|
+
if TYPE_CHECKING:
|
|
40
|
+
from pyinfra.connectors.util import CommandOutput
|
|
41
|
+
|
|
39
42
|
|
|
40
43
|
class OperationMeta:
|
|
41
44
|
_hash: str
|
|
42
45
|
|
|
43
|
-
|
|
46
|
+
_combined_output: Optional["CommandOutput"] = None
|
|
44
47
|
_commands: Optional[list[Any]] = None
|
|
45
|
-
_maybe_is_change: bool = False
|
|
48
|
+
_maybe_is_change: Optional[bool] = False
|
|
46
49
|
_success: Optional[bool] = None
|
|
47
50
|
|
|
48
|
-
def __init__(self, hash, is_change
|
|
51
|
+
def __init__(self, hash, is_change: Optional[bool]):
|
|
49
52
|
self._hash = hash
|
|
50
53
|
self._maybe_is_change = is_change
|
|
51
54
|
|
|
@@ -57,7 +60,7 @@ class OperationMeta:
|
|
|
57
60
|
if self._commands is not None:
|
|
58
61
|
return (
|
|
59
62
|
"OperationMeta(executed=True, "
|
|
60
|
-
f"
|
|
63
|
+
f"success={self.did_succeed}, hash={self._hash}, commands={len(self._commands)})"
|
|
61
64
|
)
|
|
62
65
|
return (
|
|
63
66
|
"OperationMeta(executed=False, "
|
|
@@ -69,13 +72,13 @@ class OperationMeta:
|
|
|
69
72
|
self,
|
|
70
73
|
success: bool,
|
|
71
74
|
commands: list[Any],
|
|
72
|
-
|
|
75
|
+
combined_output: "CommandOutput",
|
|
73
76
|
) -> None:
|
|
74
77
|
if self.is_complete():
|
|
75
78
|
raise RuntimeError("Cannot complete an already complete operation")
|
|
76
79
|
self._success = success
|
|
77
80
|
self._commands = commands
|
|
78
|
-
self.
|
|
81
|
+
self._combined_output = combined_output
|
|
79
82
|
|
|
80
83
|
def is_complete(self) -> bool:
|
|
81
84
|
return self._success is not None
|
|
@@ -84,10 +87,17 @@ class OperationMeta:
|
|
|
84
87
|
if not self.is_complete():
|
|
85
88
|
raise RuntimeError("Cannot evaluate operation result before execution")
|
|
86
89
|
|
|
87
|
-
def
|
|
88
|
-
self._raise_if_not_complete()
|
|
90
|
+
def _did_change(self) -> bool:
|
|
89
91
|
return bool(self._success and len(self._commands or []) > 0)
|
|
90
92
|
|
|
93
|
+
@property
|
|
94
|
+
def did_change(self):
|
|
95
|
+
return context.host.when(self._did_change)
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def did_not_change(self):
|
|
99
|
+
return context.host.when(lambda: not self._did_change())
|
|
100
|
+
|
|
91
101
|
def did_succeed(self) -> bool:
|
|
92
102
|
self._raise_if_not_complete()
|
|
93
103
|
return self._success is True
|
|
@@ -96,19 +106,32 @@ class OperationMeta:
|
|
|
96
106
|
self._raise_if_not_complete()
|
|
97
107
|
return self._success is False
|
|
98
108
|
|
|
99
|
-
#
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
109
|
+
# TODO: deprecated, remove in v4
|
|
110
|
+
@property
|
|
111
|
+
def changed(self) -> bool:
|
|
112
|
+
if self.is_complete():
|
|
113
|
+
return self._did_change()
|
|
114
|
+
|
|
115
|
+
if self._maybe_is_change is not None:
|
|
116
|
+
return self._maybe_is_change
|
|
117
|
+
|
|
118
|
+
op_data = context.state.get_op_data_for_host(context.host, self._hash)
|
|
119
|
+
cmd_gen = op_data.command_generator
|
|
120
|
+
for _ in cmd_gen():
|
|
121
|
+
return True
|
|
122
|
+
return False
|
|
104
123
|
|
|
105
124
|
@property
|
|
106
|
-
def stdout_lines(self):
|
|
107
|
-
|
|
125
|
+
def stdout_lines(self) -> list[str]:
|
|
126
|
+
self._raise_if_not_complete()
|
|
127
|
+
assert self._combined_output is not None
|
|
128
|
+
return self._combined_output.stdout_lines
|
|
108
129
|
|
|
109
130
|
@property
|
|
110
|
-
def stderr_lines(self):
|
|
111
|
-
|
|
131
|
+
def stderr_lines(self) -> list[str]:
|
|
132
|
+
self._raise_if_not_complete()
|
|
133
|
+
assert self._combined_output is not None
|
|
134
|
+
return self._combined_output.stderr_lines
|
|
112
135
|
|
|
113
136
|
@property
|
|
114
137
|
def stdout(self) -> str:
|
|
@@ -118,14 +141,6 @@ class OperationMeta:
|
|
|
118
141
|
def stderr(self) -> str:
|
|
119
142
|
return "\n".join(self.stderr_lines)
|
|
120
143
|
|
|
121
|
-
# TODO: deprecated, remove in v4
|
|
122
|
-
@property
|
|
123
|
-
def changed(self) -> int:
|
|
124
|
-
if not self.is_complete():
|
|
125
|
-
logger.warning("Checking changed before execution can give unexpected results")
|
|
126
|
-
return self._maybe_is_change
|
|
127
|
-
return self.did_change()
|
|
128
|
-
|
|
129
144
|
|
|
130
145
|
def add_op(state: State, op_func, *args, **kwargs):
|
|
131
146
|
"""
|
|
@@ -164,6 +179,8 @@ P = ParamSpec("P")
|
|
|
164
179
|
def operation(
|
|
165
180
|
is_idempotent: bool = True,
|
|
166
181
|
idempotent_notice: Optional[str] = None,
|
|
182
|
+
is_deprecated: bool = False,
|
|
183
|
+
deprecated_for: Optional[str] = None,
|
|
167
184
|
_set_in_op: bool = True,
|
|
168
185
|
) -> Callable[[Callable[P, Generator]], PyinfraOperation[P]]:
|
|
169
186
|
"""
|
|
@@ -175,6 +192,8 @@ def operation(
|
|
|
175
192
|
def decorator(f: Callable[P, Generator]) -> PyinfraOperation[P]:
|
|
176
193
|
f.is_idempotent = is_idempotent # type: ignore[attr-defined]
|
|
177
194
|
f.idempotent_notice = idempotent_notice # type: ignore[attr-defined]
|
|
195
|
+
f.is_deprecated = is_deprecated # type: ignore[attr-defined]
|
|
196
|
+
f.deprecated_for = deprecated_for # type: ignore[attr-defined]
|
|
178
197
|
return _wrap_operation(f, _set_in_op=_set_in_op)
|
|
179
198
|
|
|
180
199
|
return decorator
|
|
@@ -192,6 +211,15 @@ def _wrap_operation(func: Callable[P, Generator], _set_in_op: bool = True) -> Py
|
|
|
192
211
|
+ "function to call the underlying operation."
|
|
193
212
|
)
|
|
194
213
|
|
|
214
|
+
if func.is_deprecated: # type: ignore[attr-defined]
|
|
215
|
+
if func.deprecated_for: # type: ignore[attr-defined]
|
|
216
|
+
logger.warning(
|
|
217
|
+
f"The {get_operation_name_from_func(func)} operation is "
|
|
218
|
+
+ f"deprecated, please use: {func.deprecated_for}", # type: ignore[attr-defined] # noqa
|
|
219
|
+
)
|
|
220
|
+
else:
|
|
221
|
+
logger.warning(f"The {get_operation_name_from_func(func)} operation is deprecated")
|
|
222
|
+
|
|
195
223
|
# Configure operation
|
|
196
224
|
#
|
|
197
225
|
# Get the meta kwargs (globals that apply to all hosts)
|
|
@@ -217,7 +245,12 @@ def _wrap_operation(func: Callable[P, Generator], _set_in_op: bool = True) -> Py
|
|
|
217
245
|
break
|
|
218
246
|
|
|
219
247
|
if has_run:
|
|
220
|
-
return OperationMeta(op_hash)
|
|
248
|
+
return OperationMeta(op_hash, is_change=False)
|
|
249
|
+
|
|
250
|
+
# Grab a reference to any *current* deploy data as this may change when
|
|
251
|
+
# we later evaluate the operation at runtime.This means we put back the
|
|
252
|
+
# expected deploy data.
|
|
253
|
+
current_deploy_data = host.current_deploy_data
|
|
221
254
|
|
|
222
255
|
# "Run" operation - here we make a generator that will yield out actual commands to execute
|
|
223
256
|
# and, if we're diff-ing, we then iterate the generator now to determine if any changes
|
|
@@ -226,13 +259,14 @@ def _wrap_operation(func: Callable[P, Generator], _set_in_op: bool = True) -> Py
|
|
|
226
259
|
def command_generator() -> Iterator[PyinfraCommand]:
|
|
227
260
|
# Check global _if_ argument function and do nothing if returns False
|
|
228
261
|
if state.is_executing:
|
|
229
|
-
|
|
230
|
-
if
|
|
262
|
+
_ifs = global_arguments.get("_if")
|
|
263
|
+
if _ifs and not all(_if() for _if in _ifs):
|
|
231
264
|
return
|
|
232
265
|
|
|
233
266
|
host.in_op = _set_in_op
|
|
234
267
|
host.current_op_hash = op_hash
|
|
235
268
|
host.current_op_global_arguments = global_arguments
|
|
269
|
+
host.current_op_deploy_data = current_deploy_data
|
|
236
270
|
|
|
237
271
|
try:
|
|
238
272
|
for command in func(*args, **kwargs):
|
|
@@ -243,10 +277,12 @@ def _wrap_operation(func: Callable[P, Generator], _set_in_op: bool = True) -> Py
|
|
|
243
277
|
host.in_op = False
|
|
244
278
|
host.current_op_hash = None
|
|
245
279
|
host.current_op_global_arguments = None
|
|
280
|
+
host.current_op_deploy_data = None
|
|
246
281
|
|
|
247
|
-
op_is_change =
|
|
282
|
+
op_is_change = None
|
|
248
283
|
if state.should_check_for_changes():
|
|
249
|
-
|
|
284
|
+
op_is_change = False
|
|
285
|
+
for _ in command_generator():
|
|
250
286
|
op_is_change = True
|
|
251
287
|
break
|
|
252
288
|
else:
|
|
@@ -279,6 +315,15 @@ def _wrap_operation(func: Callable[P, Generator], _set_in_op: bool = True) -> Py
|
|
|
279
315
|
return cast(PyinfraOperation[P], decorated_func)
|
|
280
316
|
|
|
281
317
|
|
|
318
|
+
def get_operation_name_from_func(func):
|
|
319
|
+
if func.__module__:
|
|
320
|
+
module_bits = func.__module__.split(".")
|
|
321
|
+
module_name = module_bits[-1]
|
|
322
|
+
return "{0}.{1}".format(module_name, func.__name__)
|
|
323
|
+
else:
|
|
324
|
+
return func.__name__
|
|
325
|
+
|
|
326
|
+
|
|
282
327
|
def generate_operation_name(func, host, kwargs, global_arguments):
|
|
283
328
|
# Generate an operation name if needed (Module/Operation format)
|
|
284
329
|
name = global_arguments.get("name")
|
|
@@ -287,14 +332,7 @@ def generate_operation_name(func, host, kwargs, global_arguments):
|
|
|
287
332
|
names = {name}
|
|
288
333
|
else:
|
|
289
334
|
add_args = True
|
|
290
|
-
|
|
291
|
-
if func.__module__:
|
|
292
|
-
module_bits = func.__module__.split(".")
|
|
293
|
-
module_name = module_bits[-1]
|
|
294
|
-
name = "{0}/{1}".format(module_name.title(), func.__name__.title())
|
|
295
|
-
else:
|
|
296
|
-
name = func.__name__
|
|
297
|
-
|
|
335
|
+
name = get_operation_name_from_func(func)
|
|
298
336
|
names = {name}
|
|
299
337
|
|
|
300
338
|
if host.current_deploy_name:
|
|
@@ -67,17 +67,16 @@ def _run_host_op(state: "State", host: "Host", op_hash: str) -> Optional[bool]:
|
|
|
67
67
|
timeout = global_arguments.get("_timeout", 0)
|
|
68
68
|
|
|
69
69
|
executor_kwarg_keys = CONNECTOR_ARGUMENT_KEYS
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
)
|
|
70
|
+
# See: https://github.com/python/mypy/issues/10371
|
|
71
|
+
base_connector_arguments: ConnectorArguments = cast(
|
|
72
|
+
ConnectorArguments,
|
|
73
|
+
{key: global_arguments[key] for key in executor_kwarg_keys if key in global_arguments}, # type: ignore[literal-required] # noqa
|
|
75
74
|
)
|
|
76
75
|
|
|
77
76
|
did_error = False
|
|
78
77
|
executed_commands = 0
|
|
79
78
|
commands = []
|
|
80
|
-
|
|
79
|
+
all_output_lines: list[OutputLine] = []
|
|
81
80
|
|
|
82
81
|
for command in op_data.command_generator():
|
|
83
82
|
commands.append(command)
|
|
@@ -103,19 +102,19 @@ def _run_host_op(state: "State", host: "Host", op_hash: str) -> Optional[bool]:
|
|
|
103
102
|
)
|
|
104
103
|
|
|
105
104
|
elif isinstance(command, StringCommand):
|
|
106
|
-
|
|
105
|
+
output_lines = CommandOutput([])
|
|
107
106
|
try:
|
|
108
|
-
status,
|
|
107
|
+
status, output_lines = command.execute(
|
|
109
108
|
state,
|
|
110
109
|
host,
|
|
111
110
|
connector_arguments,
|
|
112
111
|
)
|
|
113
112
|
except (timeout_error, socket_error, SSHException) as e:
|
|
114
113
|
log_host_command_error(host, e, timeout=timeout)
|
|
115
|
-
|
|
114
|
+
all_output_lines.extend(output_lines)
|
|
116
115
|
# If we failed and have not already printed the stderr, print it
|
|
117
116
|
if status is False and not state.print_output:
|
|
118
|
-
print_host_combined_output(host,
|
|
117
|
+
print_host_combined_output(host, output_lines)
|
|
119
118
|
|
|
120
119
|
else:
|
|
121
120
|
try:
|
|
@@ -170,7 +169,7 @@ def _run_host_op(state: "State", host: "Host", op_hash: str) -> Optional[bool]:
|
|
|
170
169
|
op_data.operation_meta.set_complete(
|
|
171
170
|
op_success,
|
|
172
171
|
commands,
|
|
173
|
-
|
|
172
|
+
CommandOutput(all_output_lines),
|
|
174
173
|
)
|
|
175
174
|
|
|
176
175
|
return return_status
|
|
@@ -344,10 +344,19 @@ class State:
|
|
|
344
344
|
def get_results_for_host(self, host: "Host") -> StateHostResults:
|
|
345
345
|
return self.results[host]
|
|
346
346
|
|
|
347
|
-
def get_op_data_for_host(
|
|
347
|
+
def get_op_data_for_host(
|
|
348
|
+
self,
|
|
349
|
+
host: "Host",
|
|
350
|
+
op_hash: str,
|
|
351
|
+
) -> StateOperationHostData:
|
|
348
352
|
return self.ops[host][op_hash]
|
|
349
353
|
|
|
350
|
-
def set_op_data_for_host(
|
|
354
|
+
def set_op_data_for_host(
|
|
355
|
+
self,
|
|
356
|
+
host: "Host",
|
|
357
|
+
op_hash: str,
|
|
358
|
+
op_data: StateOperationHostData,
|
|
359
|
+
):
|
|
351
360
|
self.ops[host][op_hash] = op_data
|
|
352
361
|
|
|
353
362
|
def activate_host(self, host: "Host"):
|
|
@@ -84,7 +84,7 @@ class BaseConnector(abc.ABC):
|
|
|
84
84
|
|
|
85
85
|
@staticmethod
|
|
86
86
|
@abc.abstractmethod
|
|
87
|
-
def make_names_data(
|
|
87
|
+
def make_names_data(name: str) -> Iterator[tuple[str, dict, list[str]]]:
|
|
88
88
|
"""
|
|
89
89
|
Generates hosts/data/groups information for inventory. This allows a
|
|
90
90
|
single connector reference to generate multiple target hosts.
|
|
@@ -40,17 +40,17 @@ class ChrootConnector(BaseConnector):
|
|
|
40
40
|
self.local = LocalConnector(state, host)
|
|
41
41
|
|
|
42
42
|
@staticmethod
|
|
43
|
-
def make_names_data(
|
|
44
|
-
if not
|
|
43
|
+
def make_names_data(name: Optional[str] = None):
|
|
44
|
+
if not name:
|
|
45
45
|
raise InventoryError("No directory provided!")
|
|
46
46
|
|
|
47
47
|
show_warning()
|
|
48
48
|
|
|
49
|
-
yield "@chroot/{0}".format(
|
|
50
|
-
"chroot_directory": "/{0}".format(
|
|
49
|
+
yield "@chroot/{0}".format(name), {
|
|
50
|
+
"chroot_directory": "/{0}".format(name.lstrip("/")),
|
|
51
51
|
}, ["@chroot"]
|
|
52
52
|
|
|
53
|
-
def connect(self):
|
|
53
|
+
def connect(self) -> None:
|
|
54
54
|
self.local.connect()
|
|
55
55
|
|
|
56
56
|
chroot_directory = self.host.data.chroot_directory
|
|
@@ -65,7 +65,6 @@ class ChrootConnector(BaseConnector):
|
|
|
65
65
|
raise ConnectError(e.args[0])
|
|
66
66
|
|
|
67
67
|
self.host.connector_data["chroot_directory"] = chroot_directory
|
|
68
|
-
return True
|
|
69
68
|
|
|
70
69
|
def run_shell_command(
|
|
71
70
|
self,
|