pyinfra 2.9.2__tar.gz → 3.0__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.0/CHANGELOG.md +63 -0
- {pyinfra-2.9.2/pyinfra.egg-info → pyinfra-3.0}/PKG-INFO +72 -15
- {pyinfra-2.9.2 → pyinfra-3.0}/README.md +12 -10
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/__init__.py +3 -0
- pyinfra-3.0/pyinfra/api/arguments.py +345 -0
- pyinfra-3.0/pyinfra/api/arguments_typed.py +80 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/command.py +68 -53
- pyinfra-3.0/pyinfra/api/config.py +231 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/connect.py +1 -1
- pyinfra-3.0/pyinfra/api/connectors.py +27 -0
- pyinfra-3.0/pyinfra/api/deploy.py +87 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/exceptions.py +33 -8
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/facts.py +102 -137
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/host.py +150 -82
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/inventory.py +21 -25
- pyinfra-3.0/pyinfra/api/operation.py +438 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/operations.py +102 -148
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/state.py +137 -79
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/api/util.py +79 -86
- pyinfra-3.0/pyinfra/connectors/base.py +147 -0
- pyinfra-3.0/pyinfra/connectors/chroot.py +203 -0
- pyinfra-3.0/pyinfra/connectors/docker.py +288 -0
- pyinfra-3.0/pyinfra/connectors/dockerssh.py +291 -0
- pyinfra-3.0/pyinfra/connectors/local.py +232 -0
- pyinfra-3.0/pyinfra/connectors/ssh.py +628 -0
- pyinfra-3.0/pyinfra/connectors/ssh_util.py +114 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/connectors/sshuserclient/client.py +5 -3
- pyinfra-3.0/pyinfra/connectors/terraform.py +122 -0
- pyinfra-3.0/pyinfra/connectors/util.py +402 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/connectors/vagrant.py +60 -53
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/context.py +4 -2
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/apk.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/apt.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/brew.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/bsdinit.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/cargo.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/choco.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/deb.py +7 -2
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/dnf.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/docker.py +19 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/files.py +47 -32
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/gem.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/git.py +3 -1
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/gpg.py +3 -1
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/hardware.py +34 -24
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/iptables.py +5 -3
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/launchd.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/lxd.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/mysql.py +13 -6
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/npm.py +1 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/openrc.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/pacman.py +6 -2
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/pip.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/pkg.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/pkgin.py +2 -0
- pyinfra-2.9.2/pyinfra/facts/postgresql.py → pyinfra-3.0/pyinfra/facts/postgres.py +13 -10
- pyinfra-3.0/pyinfra/facts/postgresql.py +11 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/rpm.py +12 -9
- pyinfra-3.0/pyinfra/facts/runit.py +68 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/selinux.py +3 -1
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/server.py +80 -36
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/snap.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/systemd.py +31 -12
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/sysvinit.py +10 -10
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/upstart.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/util/packaging.py +7 -4
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/vzctl.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/xbps.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/yum.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/zypper.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/local.py +4 -5
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/apk.py +6 -4
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/apt.py +46 -65
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/brew.py +17 -22
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/bsdinit.py +9 -7
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/cargo.py +4 -2
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/choco.py +4 -2
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/dnf.py +19 -23
- pyinfra-3.0/pyinfra/operations/docker.py +339 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/files.py +188 -386
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/gem.py +4 -2
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/git.py +24 -53
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/iptables.py +29 -35
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/launchd.py +6 -7
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/lxd.py +8 -13
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/mysql.py +62 -81
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/npm.py +9 -2
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/openrc.py +6 -4
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/pacman.py +7 -8
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/pip.py +25 -24
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/pkg.py +4 -2
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/pkgin.py +6 -4
- pyinfra-2.9.2/pyinfra/operations/postgresql.py → pyinfra-3.0/pyinfra/operations/postgres.py +47 -89
- pyinfra-3.0/pyinfra/operations/postgresql.py +30 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/puppet.py +3 -1
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/python.py +8 -19
- pyinfra-3.0/pyinfra/operations/runit.py +182 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/selinux.py +47 -44
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/server.py +111 -127
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/snap.py +4 -4
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/ssh.py +20 -33
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/systemd.py +19 -15
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/sysvinit.py +9 -16
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/upstart.py +9 -7
- pyinfra-3.0/pyinfra/operations/util/__init__.py +12 -0
- pyinfra-3.0/pyinfra/operations/util/docker.py +177 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/util/files.py +24 -16
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/util/packaging.py +55 -57
- pyinfra-3.0/pyinfra/operations/util/service.py +46 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/vzctl.py +12 -10
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/xbps.py +6 -4
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/yum.py +18 -22
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/zypper.py +12 -13
- pyinfra-3.0/pyinfra/version.py +9 -0
- {pyinfra-2.9.2 → pyinfra-3.0/pyinfra.egg-info}/PKG-INFO +72 -15
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra.egg-info/SOURCES.txt +10 -16
- pyinfra-3.0/pyinfra.egg-info/entry_points.txt +11 -0
- pyinfra-3.0/pyinfra.egg-info/requires.txt +67 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/__main__.py +4 -3
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/commands.py +7 -2
- pyinfra-3.0/pyinfra_cli/exceptions.py +163 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/inventory.py +40 -6
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/log.py +17 -3
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/main.py +133 -90
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/prints.py +95 -127
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/util.py +62 -29
- pyinfra-3.0/pyproject.toml +19 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/setup.cfg +1 -1
- {pyinfra-2.9.2 → pyinfra-3.0}/setup.py +28 -29
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api.py +2 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_arguments.py +13 -13
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_deploys.py +28 -29
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_facts.py +60 -98
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_operations.py +101 -201
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_cli/test_cli.py +18 -49
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_cli/test_cli_deploy.py +11 -37
- pyinfra-3.0/tests/test_cli/test_cli_exceptions.py +86 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_cli/util.py +1 -1
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_chroot.py +6 -6
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_docker.py +4 -4
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_dockerssh.py +38 -50
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_local.py +11 -12
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_ssh.py +105 -93
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_terraform.py +9 -15
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_util.py +24 -46
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_vagrant.py +7 -7
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_global_arguments.py +2 -2
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_operations.py +7 -51
- pyinfra-2.9.2/CHANGELOG.md +0 -322
- pyinfra-2.9.2/pyinfra/api/arguments.py +0 -333
- pyinfra-2.9.2/pyinfra/api/config.py +0 -124
- pyinfra-2.9.2/pyinfra/api/connectors.py +0 -46
- pyinfra-2.9.2/pyinfra/api/deploy.py +0 -118
- pyinfra-2.9.2/pyinfra/api/operation.py +0 -396
- pyinfra-2.9.2/pyinfra/api/operation.pyi +0 -117
- pyinfra-2.9.2/pyinfra/connectors/ansible.py +0 -171
- pyinfra-2.9.2/pyinfra/connectors/chroot.py +0 -212
- pyinfra-2.9.2/pyinfra/connectors/docker.py +0 -305
- pyinfra-2.9.2/pyinfra/connectors/dockerssh.py +0 -313
- pyinfra-2.9.2/pyinfra/connectors/local.py +0 -244
- pyinfra-2.9.2/pyinfra/connectors/mech.py +0 -186
- pyinfra-2.9.2/pyinfra/connectors/pyinfrawinrmsession/__init__.py +0 -28
- pyinfra-2.9.2/pyinfra/connectors/ssh.py +0 -711
- pyinfra-2.9.2/pyinfra/connectors/terraform.py +0 -101
- pyinfra-2.9.2/pyinfra/connectors/util.py +0 -328
- pyinfra-2.9.2/pyinfra/connectors/winrm.py +0 -320
- pyinfra-2.9.2/pyinfra/facts/windows.py +0 -366
- pyinfra-2.9.2/pyinfra/facts/windows_files.py +0 -90
- pyinfra-2.9.2/pyinfra/operations/util/service.py +0 -58
- pyinfra-2.9.2/pyinfra/operations/windows.py +0 -59
- pyinfra-2.9.2/pyinfra/operations/windows_files.py +0 -551
- pyinfra-2.9.2/pyinfra/version.py +0 -6
- pyinfra-2.9.2/pyinfra.egg-info/entry_points.txt +0 -14
- pyinfra-2.9.2/pyinfra.egg-info/requires.txt +0 -76
- pyinfra-2.9.2/pyinfra_cli/exceptions.py +0 -127
- pyinfra-2.9.2/pyproject.toml +0 -22
- pyinfra-2.9.2/tests/__init__.py +0 -12
- pyinfra-2.9.2/tests/paramiko_util.py +0 -103
- pyinfra-2.9.2/tests/test_cli/test_cli_exceptions.py +0 -55
- pyinfra-2.9.2/tests/test_connectors/__init__.py +0 -0
- pyinfra-2.9.2/tests/test_connectors/test_ansible.py +0 -64
- pyinfra-2.9.2/tests/test_connectors/test_mech.py +0 -126
- pyinfra-2.9.2/tests/test_connectors/test_winrm.py +0 -76
- pyinfra-2.9.2/tests/util.py +0 -430
- {pyinfra-2.9.2 → pyinfra-3.0}/LICENSE.md +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/MANIFEST.in +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/__init__.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/__main__.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/connectors/__init__.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/connectors/sshuserclient/__init__.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/connectors/sshuserclient/config.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/__init__.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/util/__init__.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/util/databases.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/facts/util/win_files.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/operations/__init__.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/progress.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra/py.typed +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra.egg-info/dependency_links.txt +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra.egg-info/top_level.txt +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/__init__.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/pyinfra_cli/virtualenv.py +0 -0
- {pyinfra-2.9.2/pyinfra/operations/util → pyinfra-3.0/tests/test_api}/__init__.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_command.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_config.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_host.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_inventory.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_api/test_api_util.py +0 -0
- {pyinfra-2.9.2/tests/test_api → pyinfra-3.0/tests/test_cli}/__init__.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_cli/test_cli_util.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_cli/test_context_objects.py +0 -0
- {pyinfra-2.9.2/tests/test_cli → pyinfra-3.0/tests/test_connectors}/__init__.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_connectors/test_sshuserclient.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_facts.py +0 -0
- {pyinfra-2.9.2 → pyinfra-3.0}/tests/test_operations_utils.py +0 -0
pyinfra-3.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# v3.0
|
|
2
|
+
|
|
3
|
+
Welcome to pyinfra v3! This version is the biggest overhaul of pyinfra since it was created back in 2015. Most v2 deployment code should be automatically compatible, but as always be aware. Major changes:
|
|
4
|
+
|
|
5
|
+
### Runtime operation execution
|
|
6
|
+
|
|
7
|
+
pyinfra now executes operations at runtime, rather than pre-generating commands. Although the change isn't noticeable this fixes an entire class of bugs and confusion. See the [limitations](https://docs.pyinfra.com/en/2.x/deploy-process.html#limitations) section in the v2 docs. All of those issues are now a thing of the past.
|
|
8
|
+
|
|
9
|
+
This represents a huge overhaul of pyinfra's internals and should be a huge improvement for users.
|
|
10
|
+
|
|
11
|
+
Care has been taken to reduce the overhead of this change which still supports the same diffs and change proposal mechanism.
|
|
12
|
+
|
|
13
|
+
### CLI flow & prompts
|
|
14
|
+
|
|
15
|
+
The pyinfra CLI will now prompt (instead of ignore, or immediately exit) when problems are encountered, allowing the user to choose to continue. Additionally an approval step is added before executing changes (this can be skipped with `-y` or setting the `PYINFRA_YES` environment variable).
|
|
16
|
+
|
|
17
|
+
### Extendable connectors API, typing overhaul
|
|
18
|
+
|
|
19
|
+
v3 of pyinfra includes for the first time a (mostly) typed internal API with proper support for IDE linting. There's a whole new connectors API that provides a framework for building new connectors.
|
|
20
|
+
|
|
21
|
+
### Breaking changes
|
|
22
|
+
|
|
23
|
+
- Rename `_use_sudo_password` argument to `_sudo_password`
|
|
24
|
+
- Remove `winrm` connector and `windows*` operations/facts, moving to [`pyinfra-windows`](https://github.com/pyinfra-dev/pyinfra-windows)
|
|
25
|
+
- The deploy decorator must now be called, ie used as `@deploy()`, and is now typed
|
|
26
|
+
- Remove broken Ansible inventory connector
|
|
27
|
+
|
|
28
|
+
### Operations & Facts
|
|
29
|
+
|
|
30
|
+
- Add `docker.container`, `docker.image`, `docker.volume`, `docker.network` & `docker.prune` operations (@apecnascimento)
|
|
31
|
+
- Add `runit.service` operation and `RunitStatus` fact (@lemmi)
|
|
32
|
+
- Add `TmpDir` fact
|
|
33
|
+
- Add `services` argument to systemd facts for filtering
|
|
34
|
+
- Add type hints for all the operations (@stone-w4tch3r)
|
|
35
|
+
- Lowercase pip packages properly (PEP-0426)
|
|
36
|
+
- Rename `postgresql` -> `postgres` operations & facts (old ones still work)
|
|
37
|
+
- Improve IP/MAC parsing in `NetworkDevices` fact (@sudoBash418)
|
|
38
|
+
- Enable getting `Home` fact for other users (@matthijskooijman)
|
|
39
|
+
- Use users correct home directory in `server.user_authorized_keys` operation (@matthijskooijman)
|
|
40
|
+
- Fix `destination`/`not_destination` arguments in `iptables.rule` operation
|
|
41
|
+
- Fix remote dirs when executing from Windows in `files.sync` operation (@Renerick)
|
|
42
|
+
- Fix quoting of systemd unit names (@martenlienen)
|
|
43
|
+
|
|
44
|
+
### Other Changes
|
|
45
|
+
|
|
46
|
+
- Add new `_if` global argument to control operation execution at runtime
|
|
47
|
+
- Add `--debug-all` flag to set debug logging for all packages
|
|
48
|
+
- Retry SSH connections on failure (configurable, see [SSH connector](https://docs.pyinfra.com/en/3.x/connectors/ssh.html#available-data)) (@fwiesel)
|
|
49
|
+
- Documentation typo fixes (@szepeviktor, @sudoBash418)
|
|
50
|
+
- Fix handling of binary files in Docker connector (@matthijskooijman)
|
|
51
|
+
- Add `will_change` attribute and `did_change` context manager to `OperationMeta`
|
|
52
|
+
- Replace use of `pkg_resources` with `importlib.metadata` (@diazona)
|
|
53
|
+
- Fix identifying Python inventory files as modules (@martenlienen)
|
|
54
|
+
- Fix typed arguments order (@cdleonard)
|
|
55
|
+
- Check that fact commands don't take global arguments (@martenlienen)
|
|
56
|
+
|
|
57
|
+
# v2.x
|
|
58
|
+
|
|
59
|
+
[See this file in the `2.x` branch](https://github.com/Fizzadar/pyinfra/blob/2.x/CHANGELOG.md).
|
|
60
|
+
|
|
61
|
+
# v1.x
|
|
62
|
+
|
|
63
|
+
[See this file in the `1.x` branch](https://github.com/Fizzadar/pyinfra/blob/1.x/CHANGELOG.md).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyinfra
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0
|
|
4
4
|
Summary: pyinfra automates/provisions/manages/deploys infrastructure.
|
|
5
5
|
Home-page: https://pyinfra.com
|
|
6
6
|
Author: Nick / Fizzadar
|
|
@@ -16,20 +16,75 @@ Classifier: Intended Audience :: Information Technology
|
|
|
16
16
|
Classifier: License :: OSI Approved :: MIT License
|
|
17
17
|
Classifier: Operating System :: OS Independent
|
|
18
18
|
Classifier: Programming Language :: Python :: 3
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
21
19
|
Classifier: Programming Language :: Python :: 3.8
|
|
22
20
|
Classifier: Programming Language :: Python :: 3.9
|
|
23
21
|
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
24
|
Classifier: Topic :: System :: Systems Administration
|
|
25
25
|
Classifier: Topic :: System :: Installation/Setup
|
|
26
26
|
Classifier: Topic :: Utilities
|
|
27
|
+
Requires-Python: >=3.8
|
|
27
28
|
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE.md
|
|
30
|
+
Requires-Dist: gevent>=1.5
|
|
31
|
+
Requires-Dist: paramiko<4,>=2.7
|
|
32
|
+
Requires-Dist: click>2
|
|
33
|
+
Requires-Dist: jinja2<4,>2
|
|
34
|
+
Requires-Dist: python-dateutil<3,>2
|
|
35
|
+
Requires-Dist: setuptools
|
|
36
|
+
Requires-Dist: configparser
|
|
37
|
+
Requires-Dist: pywinrm
|
|
38
|
+
Requires-Dist: typeguard
|
|
39
|
+
Requires-Dist: distro<2,>=1.6
|
|
40
|
+
Requires-Dist: packaging>=16.1
|
|
41
|
+
Requires-Dist: graphlib_backport; python_version < "3.9"
|
|
42
|
+
Requires-Dist: typing-extensions; python_version < "3.11"
|
|
43
|
+
Requires-Dist: importlib_metadata>=3.6; python_version < "3.10"
|
|
28
44
|
Provides-Extra: test
|
|
45
|
+
Requires-Dist: pytest==8.2.1; extra == "test"
|
|
46
|
+
Requires-Dist: coverage==7.5.1; extra == "test"
|
|
47
|
+
Requires-Dist: pytest-cov==5.0.0; extra == "test"
|
|
48
|
+
Requires-Dist: black==24.4.2; extra == "test"
|
|
49
|
+
Requires-Dist: isort==5.13.2; extra == "test"
|
|
50
|
+
Requires-Dist: flake8==7.0.0; extra == "test"
|
|
51
|
+
Requires-Dist: flake8-black==0.3.6; extra == "test"
|
|
52
|
+
Requires-Dist: flake8-isort==6.1.1; extra == "test"
|
|
53
|
+
Requires-Dist: mypy; extra == "test"
|
|
54
|
+
Requires-Dist: types-cryptography; extra == "test"
|
|
55
|
+
Requires-Dist: types-paramiko; extra == "test"
|
|
56
|
+
Requires-Dist: types-python-dateutil; extra == "test"
|
|
57
|
+
Requires-Dist: types-PyYAML; extra == "test"
|
|
58
|
+
Requires-Dist: types-setuptools; extra == "test"
|
|
29
59
|
Provides-Extra: docs
|
|
60
|
+
Requires-Dist: pyinfra-guzzle_sphinx_theme==0.16; extra == "docs"
|
|
61
|
+
Requires-Dist: myst-parser==2.0.0; extra == "docs"
|
|
62
|
+
Requires-Dist: sphinx==6.2.1; extra == "docs"
|
|
30
63
|
Provides-Extra: dev
|
|
31
|
-
|
|
32
|
-
|
|
64
|
+
Requires-Dist: pytest==8.2.1; extra == "dev"
|
|
65
|
+
Requires-Dist: coverage==7.5.1; extra == "dev"
|
|
66
|
+
Requires-Dist: pytest-cov==5.0.0; extra == "dev"
|
|
67
|
+
Requires-Dist: black==24.4.2; extra == "dev"
|
|
68
|
+
Requires-Dist: isort==5.13.2; extra == "dev"
|
|
69
|
+
Requires-Dist: flake8==7.0.0; extra == "dev"
|
|
70
|
+
Requires-Dist: flake8-black==0.3.6; extra == "dev"
|
|
71
|
+
Requires-Dist: flake8-isort==6.1.1; extra == "dev"
|
|
72
|
+
Requires-Dist: mypy; extra == "dev"
|
|
73
|
+
Requires-Dist: types-cryptography; extra == "dev"
|
|
74
|
+
Requires-Dist: types-paramiko; extra == "dev"
|
|
75
|
+
Requires-Dist: types-python-dateutil; extra == "dev"
|
|
76
|
+
Requires-Dist: types-PyYAML; extra == "dev"
|
|
77
|
+
Requires-Dist: types-setuptools; extra == "dev"
|
|
78
|
+
Requires-Dist: pyinfra-guzzle_sphinx_theme==0.16; extra == "dev"
|
|
79
|
+
Requires-Dist: myst-parser==2.0.0; extra == "dev"
|
|
80
|
+
Requires-Dist: sphinx==6.2.1; extra == "dev"
|
|
81
|
+
Requires-Dist: wheel; extra == "dev"
|
|
82
|
+
Requires-Dist: twine; extra == "dev"
|
|
83
|
+
Requires-Dist: ipython; extra == "dev"
|
|
84
|
+
Requires-Dist: ipdb; extra == "dev"
|
|
85
|
+
Requires-Dist: ipdbplugin; extra == "dev"
|
|
86
|
+
Requires-Dist: flake8-spellcheck==0.12.1; extra == "dev"
|
|
87
|
+
Requires-Dist: redbaron; extra == "dev"
|
|
33
88
|
|
|
34
89
|
<p align="center">
|
|
35
90
|
<a href="https://pyinfra.com">
|
|
@@ -37,25 +92,27 @@ License-File: LICENSE.md
|
|
|
37
92
|
</a>
|
|
38
93
|
</p>
|
|
39
94
|
|
|
40
|
-
<p
|
|
41
|
-
<
|
|
95
|
+
<p>
|
|
96
|
+
<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>
|
|
97
|
+
</p>
|
|
98
|
+
|
|
99
|
+
<p>
|
|
100
|
+
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.
|
|
42
101
|
</p>
|
|
43
102
|
|
|
44
103
|
---
|
|
45
104
|
|
|
46
|
-
<
|
|
47
|
-
<a href="https://docs.pyinfra.com"><strong>Documentation</strong></a> ⇒
|
|
105
|
+
<h3>
|
|
48
106
|
<a href="https://docs.pyinfra.com/page/getting-started.html"><strong>Getting Started</strong></a> •
|
|
49
|
-
<a href="https://
|
|
107
|
+
<a href="https://github.com/pyinfra-dev/pyinfra-examples"><strong>Examples Repo</strong></a> •
|
|
108
|
+
<a href="https://matrix.to/#/#pyinfra:matrix.org"><strong>Chat on Matrix</strong></a>
|
|
109
|
+
</h3>
|
|
110
|
+
<p>
|
|
111
|
+
<a href="https://docs.pyinfra.com"><strong>Documentation</strong></a> •
|
|
50
112
|
<a href="https://docs.pyinfra.com/page/support.html"><strong>Help & Support</strong></a> •
|
|
51
113
|
<a href="https://docs.pyinfra.com/page/contributing.html"><strong>Contributing</strong></a>
|
|
52
114
|
</p>
|
|
53
115
|
|
|
54
|
-
<p align="center">
|
|
55
|
-
Chat ⇒
|
|
56
|
-
<a href="https://matrix.to/#/#pyinfra:matrix.org"><strong><code>#pyinfra</code> on Matrix</strong></a>
|
|
57
|
-
</p>
|
|
58
|
-
|
|
59
116
|
---
|
|
60
117
|
|
|
61
118
|
Why pyinfra? Design features include:
|
|
@@ -4,25 +4,27 @@
|
|
|
4
4
|
</a>
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
-
<p
|
|
8
|
-
<
|
|
7
|
+
<p>
|
|
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
|
+
</p>
|
|
10
|
+
|
|
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.
|
|
9
13
|
</p>
|
|
10
14
|
|
|
11
15
|
---
|
|
12
16
|
|
|
13
|
-
<
|
|
14
|
-
<a href="https://docs.pyinfra.com"><strong>Documentation</strong></a> ⇒
|
|
17
|
+
<h3>
|
|
15
18
|
<a href="https://docs.pyinfra.com/page/getting-started.html"><strong>Getting Started</strong></a> •
|
|
16
|
-
<a href="https://
|
|
19
|
+
<a href="https://github.com/pyinfra-dev/pyinfra-examples"><strong>Examples Repo</strong></a> •
|
|
20
|
+
<a href="https://matrix.to/#/#pyinfra:matrix.org"><strong>Chat on Matrix</strong></a>
|
|
21
|
+
</h3>
|
|
22
|
+
<p>
|
|
23
|
+
<a href="https://docs.pyinfra.com"><strong>Documentation</strong></a> •
|
|
17
24
|
<a href="https://docs.pyinfra.com/page/support.html"><strong>Help & Support</strong></a> •
|
|
18
25
|
<a href="https://docs.pyinfra.com/page/contributing.html"><strong>Contributing</strong></a>
|
|
19
26
|
</p>
|
|
20
27
|
|
|
21
|
-
<p align="center">
|
|
22
|
-
Chat ⇒
|
|
23
|
-
<a href="https://matrix.to/#/#pyinfra:matrix.org"><strong><code>#pyinfra</code> on Matrix</strong></a>
|
|
24
|
-
</p>
|
|
25
|
-
|
|
26
28
|
---
|
|
27
29
|
|
|
28
30
|
Why pyinfra? Design features include:
|
|
@@ -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,
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import (
|
|
4
|
+
TYPE_CHECKING,
|
|
5
|
+
Any,
|
|
6
|
+
Callable,
|
|
7
|
+
Generic,
|
|
8
|
+
Iterable,
|
|
9
|
+
List,
|
|
10
|
+
Mapping,
|
|
11
|
+
Optional,
|
|
12
|
+
Type,
|
|
13
|
+
TypeVar,
|
|
14
|
+
Union,
|
|
15
|
+
cast,
|
|
16
|
+
get_type_hints,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
from typing_extensions import TypedDict
|
|
20
|
+
|
|
21
|
+
from pyinfra import context
|
|
22
|
+
from pyinfra.api.exceptions import ArgumentTypeError
|
|
23
|
+
from pyinfra.api.state import State
|
|
24
|
+
from pyinfra.api.util import raise_if_bad_type
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from pyinfra.api.config import Config
|
|
28
|
+
from pyinfra.api.host import Host
|
|
29
|
+
|
|
30
|
+
T = TypeVar("T")
|
|
31
|
+
default_sentinel = object()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ArgumentMeta(Generic[T]):
|
|
35
|
+
description: str
|
|
36
|
+
default: Callable[["Config"], T]
|
|
37
|
+
handler: Optional[Callable[["Config", T], T]]
|
|
38
|
+
|
|
39
|
+
def __init__(self, description, default, handler=None) -> None:
|
|
40
|
+
self.description = description
|
|
41
|
+
self.default = default
|
|
42
|
+
self.handler = handler
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# Connector arguments
|
|
46
|
+
# These are arguments passed to the various connectors that provide the underlying
|
|
47
|
+
# API to read/write external systems.
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# Note: ConnectorArguments is specifically not total as it's used to type many
|
|
51
|
+
# functions via Unpack and we don't want to specify every kwarg.
|
|
52
|
+
class ConnectorArguments(TypedDict, total=False):
|
|
53
|
+
# Auth arguments
|
|
54
|
+
_sudo: bool
|
|
55
|
+
_sudo_user: str
|
|
56
|
+
_use_sudo_login: bool
|
|
57
|
+
_sudo_password: str
|
|
58
|
+
_preserve_sudo_env: bool
|
|
59
|
+
_su_user: str
|
|
60
|
+
_use_su_login: bool
|
|
61
|
+
_preserve_su_env: bool
|
|
62
|
+
_su_shell: str
|
|
63
|
+
_doas: bool
|
|
64
|
+
_doas_user: str
|
|
65
|
+
|
|
66
|
+
# Shell arguments
|
|
67
|
+
_shell_executable: str
|
|
68
|
+
_chdir: str
|
|
69
|
+
_env: Mapping[str, str]
|
|
70
|
+
|
|
71
|
+
# Connector control (outside of command generation)
|
|
72
|
+
_success_exit_codes: Iterable[int]
|
|
73
|
+
_timeout: int
|
|
74
|
+
_get_pty: bool
|
|
75
|
+
_stdin: Union[str, Iterable[str]]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def generate_env(config: "Config", value: dict) -> dict:
|
|
79
|
+
env = config.ENV.copy()
|
|
80
|
+
env.update(value)
|
|
81
|
+
return env
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
auth_argument_meta: dict[str, ArgumentMeta] = {
|
|
85
|
+
"_sudo": ArgumentMeta(
|
|
86
|
+
"Execute/apply any changes with sudo.",
|
|
87
|
+
default=lambda config: config.SUDO,
|
|
88
|
+
),
|
|
89
|
+
"_sudo_user": ArgumentMeta(
|
|
90
|
+
"Execute/apply any changes with sudo as a non-root user.",
|
|
91
|
+
default=lambda config: config.SUDO_USER,
|
|
92
|
+
),
|
|
93
|
+
"_use_sudo_login": ArgumentMeta(
|
|
94
|
+
"Execute sudo with a login shell.",
|
|
95
|
+
default=lambda config: config.USE_SUDO_LOGIN,
|
|
96
|
+
),
|
|
97
|
+
"_sudo_password": ArgumentMeta(
|
|
98
|
+
"Password to sudo with. If needed and not specified pyinfra will prompt for it.",
|
|
99
|
+
default=lambda config: config.SUDO_PASSWORD,
|
|
100
|
+
),
|
|
101
|
+
"_preserve_sudo_env": ArgumentMeta(
|
|
102
|
+
"Preserve the shell environment of the connecting user when using sudo.",
|
|
103
|
+
default=lambda config: config.PRESERVE_SUDO_ENV,
|
|
104
|
+
),
|
|
105
|
+
"_su_user": ArgumentMeta(
|
|
106
|
+
"Execute/apply any changes with this user using su.",
|
|
107
|
+
default=lambda config: config.SU_USER,
|
|
108
|
+
),
|
|
109
|
+
"_use_su_login": ArgumentMeta(
|
|
110
|
+
"Execute su with a login shell.",
|
|
111
|
+
default=lambda config: config.USE_SU_LOGIN,
|
|
112
|
+
),
|
|
113
|
+
"_preserve_su_env": ArgumentMeta(
|
|
114
|
+
"Preserve the shell environment of the connecting user when using su.",
|
|
115
|
+
default=lambda config: config.PRESERVE_SU_ENV,
|
|
116
|
+
),
|
|
117
|
+
"_su_shell": ArgumentMeta(
|
|
118
|
+
"Use this shell (instead of user login shell) when using ``_su``). "
|
|
119
|
+
+ "Only available under Linux, for use when using `su` with a user that "
|
|
120
|
+
+ "has nologin/similar as their login shell.",
|
|
121
|
+
default=lambda config: config.SU_SHELL,
|
|
122
|
+
),
|
|
123
|
+
"_doas": ArgumentMeta(
|
|
124
|
+
"Execute/apply any changes with doas.",
|
|
125
|
+
default=lambda config: config.DOAS,
|
|
126
|
+
),
|
|
127
|
+
"_doas_user": ArgumentMeta(
|
|
128
|
+
"Execute/apply any changes with doas as a non-root user.",
|
|
129
|
+
default=lambda config: config.DOAS_USER,
|
|
130
|
+
),
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
shell_argument_meta: dict[str, ArgumentMeta] = {
|
|
134
|
+
"_shell_executable": ArgumentMeta(
|
|
135
|
+
"The shell executable to use for executing commands.",
|
|
136
|
+
default=lambda config: config.SHELL,
|
|
137
|
+
),
|
|
138
|
+
"_chdir": ArgumentMeta(
|
|
139
|
+
"Directory to switch to before executing the command.",
|
|
140
|
+
default=lambda _: "",
|
|
141
|
+
),
|
|
142
|
+
"_env": ArgumentMeta(
|
|
143
|
+
"Dictionary of environment variables to set.",
|
|
144
|
+
default=lambda _: {},
|
|
145
|
+
handler=generate_env,
|
|
146
|
+
),
|
|
147
|
+
"_success_exit_codes": ArgumentMeta(
|
|
148
|
+
"List of exit codes to consider a success.",
|
|
149
|
+
default=lambda _: [0],
|
|
150
|
+
),
|
|
151
|
+
"_timeout": ArgumentMeta(
|
|
152
|
+
"Timeout for *each* command executed during the operation.",
|
|
153
|
+
default=lambda _: None,
|
|
154
|
+
),
|
|
155
|
+
"_get_pty": ArgumentMeta(
|
|
156
|
+
"Whether to get a pseudoTTY when executing any commands.",
|
|
157
|
+
default=lambda _: False,
|
|
158
|
+
),
|
|
159
|
+
"_stdin": ArgumentMeta(
|
|
160
|
+
"String or buffer to send to the stdin of any commands.",
|
|
161
|
+
default=lambda _: None,
|
|
162
|
+
),
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
# Meta arguments
|
|
167
|
+
# These provide/extend additional operation metadata
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class MetaArguments(TypedDict):
|
|
171
|
+
name: str
|
|
172
|
+
_ignore_errors: bool
|
|
173
|
+
_continue_on_error: bool
|
|
174
|
+
_if: Union[List[Callable[[], bool]], Callable[[], bool], None]
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
meta_argument_meta: dict[str, ArgumentMeta] = {
|
|
178
|
+
# NOTE: name is the only non-_-prefixed argument
|
|
179
|
+
"name": ArgumentMeta(
|
|
180
|
+
"Name of the operation.",
|
|
181
|
+
default=lambda _: None,
|
|
182
|
+
),
|
|
183
|
+
"_ignore_errors": ArgumentMeta(
|
|
184
|
+
"Ignore errors when executing the operation.",
|
|
185
|
+
default=lambda config: config.IGNORE_ERRORS,
|
|
186
|
+
),
|
|
187
|
+
"_continue_on_error": ArgumentMeta(
|
|
188
|
+
(
|
|
189
|
+
"Continue executing operation commands after error. "
|
|
190
|
+
"Only applies when ``_ignore_errors`` is true."
|
|
191
|
+
),
|
|
192
|
+
default=lambda _: False,
|
|
193
|
+
),
|
|
194
|
+
"_if": ArgumentMeta(
|
|
195
|
+
"Only run this operation if these functions return True",
|
|
196
|
+
default=lambda _: [],
|
|
197
|
+
),
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
# Execution arguments
|
|
202
|
+
# These alter how pyinfra is to execute an operation. Notably these must all have the same value
|
|
203
|
+
# over every target host for the same operation.
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class ExecutionArguments(TypedDict):
|
|
207
|
+
_parallel: int
|
|
208
|
+
_run_once: bool
|
|
209
|
+
_serial: bool
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
execution_argument_meta: dict[str, ArgumentMeta] = {
|
|
213
|
+
"_parallel": ArgumentMeta(
|
|
214
|
+
"Run this operation in batches of hosts.",
|
|
215
|
+
default=lambda config: config.PARALLEL,
|
|
216
|
+
),
|
|
217
|
+
"_run_once": ArgumentMeta(
|
|
218
|
+
"Only execute this operation once, on the first host to see it.",
|
|
219
|
+
default=lambda _: False,
|
|
220
|
+
),
|
|
221
|
+
"_serial": ArgumentMeta(
|
|
222
|
+
"Run this operation host by host, rather than in parallel.",
|
|
223
|
+
default=lambda _: False,
|
|
224
|
+
),
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class AllArguments(ConnectorArguments, MetaArguments, ExecutionArguments):
|
|
229
|
+
pass
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def all_global_arguments() -> List[tuple[str, Type]]:
|
|
233
|
+
"""Return all global arguments and their types."""
|
|
234
|
+
return list(get_type_hints(AllArguments).items())
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
all_argument_meta: dict[str, ArgumentMeta] = {
|
|
238
|
+
**auth_argument_meta,
|
|
239
|
+
**shell_argument_meta,
|
|
240
|
+
**meta_argument_meta,
|
|
241
|
+
**execution_argument_meta,
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
EXECUTION_KWARG_KEYS = list(ExecutionArguments.__annotations__.keys())
|
|
245
|
+
CONNECTOR_ARGUMENT_KEYS = list(ConnectorArguments.__annotations__.keys())
|
|
246
|
+
|
|
247
|
+
__argument_docs__ = {
|
|
248
|
+
"Privilege & user escalation": (
|
|
249
|
+
auth_argument_meta,
|
|
250
|
+
"""
|
|
251
|
+
.. code:: python
|
|
252
|
+
|
|
253
|
+
# Execute a command with sudo
|
|
254
|
+
server.user(
|
|
255
|
+
name="Create pyinfra user using sudo",
|
|
256
|
+
user="pyinfra",
|
|
257
|
+
_sudo=True,
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
# Execute a command with a specific sudo password
|
|
261
|
+
server.user(
|
|
262
|
+
name="Create pyinfra user using sudo",
|
|
263
|
+
user="pyinfra",
|
|
264
|
+
_sudo=True,
|
|
265
|
+
_sudo_password="my-secret-password",
|
|
266
|
+
)
|
|
267
|
+
""",
|
|
268
|
+
),
|
|
269
|
+
"Shell control & features": (
|
|
270
|
+
shell_argument_meta,
|
|
271
|
+
"""
|
|
272
|
+
.. code:: python
|
|
273
|
+
|
|
274
|
+
# Execute from a specific directory
|
|
275
|
+
server.shell(
|
|
276
|
+
name="Bootstrap nginx params",
|
|
277
|
+
commands=["openssl dhparam -out dhparam.pem 4096"],
|
|
278
|
+
_chdir="/etc/ssl/certs",
|
|
279
|
+
)
|
|
280
|
+
""",
|
|
281
|
+
),
|
|
282
|
+
"Operation meta & callbacks": (meta_argument_meta, ""),
|
|
283
|
+
"Execution strategy": (execution_argument_meta, ""),
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def pop_global_arguments(
|
|
288
|
+
kwargs: dict[str, Any],
|
|
289
|
+
state: Optional["State"] = None,
|
|
290
|
+
host: Optional["Host"] = None,
|
|
291
|
+
keys_to_check=None,
|
|
292
|
+
) -> tuple[AllArguments, list[str]]:
|
|
293
|
+
"""
|
|
294
|
+
Pop and return operation global keyword arguments, in preferred order:
|
|
295
|
+
|
|
296
|
+
+ From the current context (a direct @operator or @deploy function being called)
|
|
297
|
+
+ From any current @deploy context (deploy kwargs)
|
|
298
|
+
+ From the host data variables
|
|
299
|
+
+ From the config variables
|
|
300
|
+
"""
|
|
301
|
+
|
|
302
|
+
state = state or context.state
|
|
303
|
+
host = host or context.host
|
|
304
|
+
|
|
305
|
+
config = state.config
|
|
306
|
+
if context.ctx_config.isset():
|
|
307
|
+
config = context.config
|
|
308
|
+
|
|
309
|
+
meta_kwargs: dict[str, Any] = host.current_deploy_kwargs or {} # type: ignore[assignment]
|
|
310
|
+
|
|
311
|
+
arguments: dict[str, Any] = {}
|
|
312
|
+
found_keys: list[str] = []
|
|
313
|
+
|
|
314
|
+
for key, type_ in all_global_arguments():
|
|
315
|
+
if keys_to_check and key not in keys_to_check:
|
|
316
|
+
continue
|
|
317
|
+
|
|
318
|
+
argument_meta = all_argument_meta[key]
|
|
319
|
+
handler = argument_meta.handler
|
|
320
|
+
default: Any = argument_meta.default(config)
|
|
321
|
+
|
|
322
|
+
host_default = getattr(host.data, key, default_sentinel)
|
|
323
|
+
if host_default is not default_sentinel:
|
|
324
|
+
default = host_default
|
|
325
|
+
|
|
326
|
+
if key in kwargs:
|
|
327
|
+
found_keys.append(key)
|
|
328
|
+
value = kwargs.pop(key)
|
|
329
|
+
else:
|
|
330
|
+
value = meta_kwargs.get(key, default)
|
|
331
|
+
|
|
332
|
+
if handler:
|
|
333
|
+
value = handler(config, value)
|
|
334
|
+
|
|
335
|
+
if value != default:
|
|
336
|
+
raise_if_bad_type(
|
|
337
|
+
value,
|
|
338
|
+
type_,
|
|
339
|
+
ArgumentTypeError,
|
|
340
|
+
f"Invalid argument `{key}`:",
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
# TODO: why is type failing here?
|
|
344
|
+
arguments[key] = value # type: ignore
|
|
345
|
+
return cast(AllArguments, arguments), found_keys
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import (
|
|
4
|
+
TYPE_CHECKING,
|
|
5
|
+
Callable,
|
|
6
|
+
Generator,
|
|
7
|
+
Generic,
|
|
8
|
+
Iterable,
|
|
9
|
+
List,
|
|
10
|
+
Mapping,
|
|
11
|
+
Optional,
|
|
12
|
+
Union,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from typing_extensions import ParamSpec, Protocol
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from pyinfra.api.operation import OperationMeta
|
|
19
|
+
|
|
20
|
+
P = ParamSpec("P")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Unfortunately we have to re-type out all of the global arguments here because
|
|
24
|
+
# Python typing doesn't (yet) support merging kwargs. This acts as the operation
|
|
25
|
+
# decorator output function which merges actual operation args/kwargs in paramspec
|
|
26
|
+
# with the global arguments available in all operations.
|
|
27
|
+
# The nature of "global arguments" is somewhat opposed to static typing as it's
|
|
28
|
+
# indirect and somewhat magic, but we are where we are.
|
|
29
|
+
class PyinfraOperation(Generic[P], Protocol):
|
|
30
|
+
_inner: Callable[P, Generator]
|
|
31
|
+
|
|
32
|
+
def __call__(
|
|
33
|
+
self,
|
|
34
|
+
#
|
|
35
|
+
# op args
|
|
36
|
+
# needs to be first
|
|
37
|
+
#
|
|
38
|
+
*args: P.args,
|
|
39
|
+
#
|
|
40
|
+
# ConnectorArguments
|
|
41
|
+
#
|
|
42
|
+
# Auth
|
|
43
|
+
_sudo: bool = False,
|
|
44
|
+
_sudo_user: Optional[str] = None,
|
|
45
|
+
_use_sudo_login: bool = False,
|
|
46
|
+
_sudo_password: Optional[str] = None,
|
|
47
|
+
_preserve_sudo_env: bool = False,
|
|
48
|
+
_su_user: Optional[str] = None,
|
|
49
|
+
_use_su_login: bool = False,
|
|
50
|
+
_preserve_su_env: bool = False,
|
|
51
|
+
_su_shell: Optional[str] = None,
|
|
52
|
+
_doas: bool = False,
|
|
53
|
+
_doas_user: Optional[str] = None,
|
|
54
|
+
# Shell arguments
|
|
55
|
+
_shell_executable: Optional[str] = None,
|
|
56
|
+
_chdir: Optional[str] = None,
|
|
57
|
+
_env: Optional[Mapping[str, str]] = None,
|
|
58
|
+
# Connector control
|
|
59
|
+
_success_exit_codes: Iterable[int] = (0,),
|
|
60
|
+
_timeout: Optional[int] = None,
|
|
61
|
+
_get_pty: bool = False,
|
|
62
|
+
_stdin: Union[None, str, list[str], tuple[str, ...]] = None,
|
|
63
|
+
#
|
|
64
|
+
# MetaArguments
|
|
65
|
+
#
|
|
66
|
+
name: Optional[str] = None,
|
|
67
|
+
_ignore_errors: bool = False,
|
|
68
|
+
_continue_on_error: bool = False,
|
|
69
|
+
_if: Union[List[Callable[[], bool]], Callable[[], bool], None] = None,
|
|
70
|
+
#
|
|
71
|
+
# ExecutionArguments
|
|
72
|
+
#
|
|
73
|
+
_parallel: Optional[int] = None,
|
|
74
|
+
_run_once: bool = False,
|
|
75
|
+
_serial: bool = False,
|
|
76
|
+
#
|
|
77
|
+
# op kwargs
|
|
78
|
+
#
|
|
79
|
+
**kwargs: P.kwargs,
|
|
80
|
+
) -> "OperationMeta": ...
|