pyinfra 3.0.dev0__py2.py3-none-any.whl → 3.0.1__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 +115 -97
- pyinfra/api/arguments_typed.py +80 -0
- pyinfra/api/command.py +5 -3
- pyinfra/api/config.py +139 -39
- pyinfra/api/connectors.py +5 -2
- pyinfra/api/deploy.py +19 -19
- pyinfra/api/exceptions.py +35 -4
- pyinfra/api/facts.py +62 -86
- pyinfra/api/host.py +102 -15
- pyinfra/api/inventory.py +4 -0
- pyinfra/api/operation.py +184 -118
- pyinfra/api/operations.py +66 -113
- pyinfra/api/state.py +53 -34
- pyinfra/api/util.py +64 -33
- pyinfra/connectors/base.py +65 -20
- pyinfra/connectors/chroot.py +15 -13
- pyinfra/connectors/docker.py +62 -72
- pyinfra/connectors/dockerssh.py +20 -19
- pyinfra/connectors/local.py +32 -22
- pyinfra/connectors/ssh.py +162 -86
- pyinfra/connectors/sshuserclient/client.py +1 -1
- pyinfra/connectors/terraform.py +57 -39
- pyinfra/connectors/util.py +26 -27
- pyinfra/connectors/vagrant.py +27 -26
- pyinfra/context.py +1 -0
- pyinfra/facts/apk.py +7 -2
- pyinfra/facts/apt.py +15 -7
- pyinfra/facts/brew.py +28 -13
- pyinfra/facts/bsdinit.py +9 -6
- pyinfra/facts/cargo.py +6 -3
- pyinfra/facts/choco.py +8 -4
- pyinfra/facts/deb.py +21 -9
- pyinfra/facts/dnf.py +11 -6
- pyinfra/facts/docker.py +30 -5
- pyinfra/facts/files.py +49 -33
- pyinfra/facts/gem.py +7 -2
- pyinfra/facts/git.py +14 -21
- pyinfra/facts/gpg.py +4 -1
- pyinfra/facts/hardware.py +186 -138
- pyinfra/facts/launchd.py +7 -2
- pyinfra/facts/lxd.py +8 -2
- pyinfra/facts/mysql.py +19 -12
- pyinfra/facts/npm.py +3 -1
- pyinfra/facts/openrc.py +8 -2
- pyinfra/facts/pacman.py +13 -5
- pyinfra/facts/pip.py +2 -0
- pyinfra/facts/pkg.py +5 -1
- pyinfra/facts/pkgin.py +7 -2
- pyinfra/facts/postgres.py +170 -0
- pyinfra/facts/postgresql.py +5 -162
- pyinfra/facts/rpm.py +21 -15
- pyinfra/facts/runit.py +70 -0
- pyinfra/facts/selinux.py +12 -4
- pyinfra/facts/server.py +240 -82
- pyinfra/facts/snap.py +8 -2
- pyinfra/facts/systemd.py +37 -13
- pyinfra/facts/sysvinit.py +7 -4
- pyinfra/facts/upstart.py +7 -2
- pyinfra/facts/util/packaging.py +3 -2
- pyinfra/facts/vzctl.py +8 -4
- pyinfra/facts/xbps.py +7 -2
- pyinfra/facts/yum.py +10 -5
- pyinfra/facts/zypper.py +9 -4
- pyinfra/operations/apk.py +5 -3
- pyinfra/operations/apt.py +28 -25
- pyinfra/operations/brew.py +60 -29
- pyinfra/operations/bsdinit.py +6 -4
- pyinfra/operations/cargo.py +3 -1
- pyinfra/operations/choco.py +3 -1
- pyinfra/operations/dnf.py +16 -20
- pyinfra/operations/docker.py +339 -0
- pyinfra/operations/files.py +187 -168
- pyinfra/operations/gem.py +3 -1
- pyinfra/operations/git.py +23 -25
- pyinfra/operations/iptables.py +33 -25
- pyinfra/operations/launchd.py +5 -6
- pyinfra/operations/lxd.py +7 -4
- pyinfra/operations/mysql.py +59 -55
- pyinfra/operations/npm.py +8 -1
- pyinfra/operations/openrc.py +5 -3
- pyinfra/operations/pacman.py +6 -7
- pyinfra/operations/pip.py +19 -12
- pyinfra/operations/pkg.py +3 -1
- pyinfra/operations/pkgin.py +5 -3
- pyinfra/operations/postgres.py +349 -0
- pyinfra/operations/postgresql.py +18 -335
- pyinfra/operations/puppet.py +3 -1
- pyinfra/operations/python.py +8 -19
- pyinfra/operations/runit.py +182 -0
- pyinfra/operations/selinux.py +47 -29
- pyinfra/operations/server.py +138 -67
- pyinfra/operations/snap.py +3 -1
- pyinfra/operations/ssh.py +18 -16
- pyinfra/operations/systemd.py +18 -12
- pyinfra/operations/sysvinit.py +7 -5
- pyinfra/operations/upstart.py +7 -5
- pyinfra/operations/util/__init__.py +12 -0
- pyinfra/operations/util/docker.py +177 -0
- pyinfra/operations/util/files.py +24 -16
- pyinfra/operations/util/packaging.py +54 -38
- pyinfra/operations/util/service.py +39 -47
- pyinfra/operations/vzctl.py +12 -10
- pyinfra/operations/xbps.py +5 -3
- pyinfra/operations/yum.py +15 -19
- pyinfra/operations/zypper.py +9 -10
- pyinfra/version.py +5 -2
- {pyinfra-3.0.dev0.dist-info → pyinfra-3.0.1.dist-info}/METADATA +51 -58
- pyinfra-3.0.1.dist-info/RECORD +168 -0
- {pyinfra-3.0.dev0.dist-info → pyinfra-3.0.1.dist-info}/WHEEL +1 -1
- {pyinfra-3.0.dev0.dist-info → pyinfra-3.0.1.dist-info}/entry_points.txt +0 -3
- pyinfra_cli/__main__.py +4 -3
- pyinfra_cli/commands.py +3 -2
- pyinfra_cli/exceptions.py +75 -43
- pyinfra_cli/inventory.py +52 -31
- pyinfra_cli/log.py +10 -2
- pyinfra_cli/main.py +88 -65
- pyinfra_cli/prints.py +37 -109
- pyinfra_cli/util.py +15 -10
- tests/test_api/test_api.py +2 -0
- tests/test_api/test_api_arguments.py +9 -9
- tests/test_api/test_api_deploys.py +15 -19
- tests/test_api/test_api_facts.py +4 -5
- tests/test_api/test_api_operations.py +18 -20
- tests/test_api/test_api_util.py +41 -2
- tests/test_cli/test_cli.py +14 -50
- tests/test_cli/test_cli_deploy.py +10 -12
- tests/test_cli/test_cli_exceptions.py +50 -19
- tests/test_cli/test_cli_inventory.py +66 -0
- tests/test_cli/util.py +1 -1
- tests/test_connectors/test_dockerssh.py +11 -8
- tests/test_connectors/test_ssh.py +88 -23
- tests/test_connectors/test_sshuserclient.py +1 -1
- tests/test_connectors/test_terraform.py +11 -8
- tests/test_connectors/test_vagrant.py +6 -6
- pyinfra/connectors/ansible.py +0 -175
- pyinfra/connectors/mech.py +0 -189
- pyinfra/connectors/pyinfrawinrmsession/__init__.py +0 -28
- pyinfra/connectors/winrm.py +0 -312
- 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 -538
- pyinfra-3.0.dev0.dist-info/RECORD +0 -170
- tests/test_connectors/test_ansible.py +0 -64
- tests/test_connectors/test_mech.py +0 -126
- {pyinfra-3.0.dev0.dist-info → pyinfra-3.0.1.dist-info}/LICENSE.md +0 -0
- {pyinfra-3.0.dev0.dist-info → pyinfra-3.0.1.dist-info}/top_level.txt +0 -0
pyinfra/operations/snap.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Manage snap packages. See https://snapcraft.io/
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
5
7
|
from pyinfra import host
|
|
6
8
|
from pyinfra.api import operation
|
|
7
9
|
from pyinfra.facts.snap import SnapPackage, SnapPackages
|
|
@@ -9,7 +11,7 @@ from pyinfra.facts.snap import SnapPackage, SnapPackages
|
|
|
9
11
|
|
|
10
12
|
@operation()
|
|
11
13
|
def package(
|
|
12
|
-
packages=None,
|
|
14
|
+
packages: str | list[str] | None = None,
|
|
13
15
|
channel="latest/stable",
|
|
14
16
|
classic=False,
|
|
15
17
|
present=True,
|
pyinfra/operations/ssh.py
CHANGED
|
@@ -4,9 +4,11 @@ Execute commands and up/download files *from* the remote host.
|
|
|
4
4
|
Eg: ``pyinfra -> inventory-host.net <-> another-host.net``
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
7
9
|
import shlex
|
|
8
10
|
|
|
9
|
-
from pyinfra import host
|
|
11
|
+
from pyinfra import host
|
|
10
12
|
from pyinfra.api import OperationError, operation
|
|
11
13
|
from pyinfra.facts.files import File, FindInFile
|
|
12
14
|
from pyinfra.facts.server import Home
|
|
@@ -15,7 +17,7 @@ from . import files
|
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
@operation()
|
|
18
|
-
def keyscan(hostname, force=False, port=22):
|
|
20
|
+
def keyscan(hostname: str, force=False, port=22):
|
|
19
21
|
"""
|
|
20
22
|
Check/add hosts to the ``~/.ssh/known_hosts`` file.
|
|
21
23
|
|
|
@@ -34,7 +36,7 @@ def keyscan(hostname, force=False, port=22):
|
|
|
34
36
|
|
|
35
37
|
homedir = host.get_fact(Home)
|
|
36
38
|
|
|
37
|
-
yield from files.directory(
|
|
39
|
+
yield from files.directory._inner(
|
|
38
40
|
"{0}/.ssh".format(homedir),
|
|
39
41
|
mode=700,
|
|
40
42
|
)
|
|
@@ -63,7 +65,7 @@ def keyscan(hostname, force=False, port=22):
|
|
|
63
65
|
|
|
64
66
|
|
|
65
67
|
@operation(is_idempotent=False)
|
|
66
|
-
def command(hostname, command, user=None, port=22):
|
|
68
|
+
def command(hostname: str, command: str, user: str | None = None, port=22):
|
|
67
69
|
"""
|
|
68
70
|
Execute commands on other servers over SSH.
|
|
69
71
|
|
|
@@ -95,11 +97,11 @@ def command(hostname, command, user=None, port=22):
|
|
|
95
97
|
|
|
96
98
|
@operation(is_idempotent=False)
|
|
97
99
|
def upload(
|
|
98
|
-
hostname,
|
|
99
|
-
filename,
|
|
100
|
-
remote_filename=None,
|
|
100
|
+
hostname: str,
|
|
101
|
+
filename: str,
|
|
102
|
+
remote_filename: str | None = None,
|
|
101
103
|
port=22,
|
|
102
|
-
user=None,
|
|
104
|
+
user: str | None = None,
|
|
103
105
|
use_remote_sudo=False,
|
|
104
106
|
ssh_keyscan=False,
|
|
105
107
|
):
|
|
@@ -123,7 +125,7 @@ def upload(
|
|
|
123
125
|
connection_target = "@".join((user, hostname))
|
|
124
126
|
|
|
125
127
|
if ssh_keyscan:
|
|
126
|
-
yield from keyscan(hostname)
|
|
128
|
+
yield from keyscan._inner(hostname)
|
|
127
129
|
|
|
128
130
|
# If we're not using sudo on the remote side, just scp the file over
|
|
129
131
|
if not use_remote_sudo:
|
|
@@ -136,7 +138,7 @@ def upload(
|
|
|
136
138
|
|
|
137
139
|
else:
|
|
138
140
|
# Otherwise - we need a temporary location for the file
|
|
139
|
-
temp_remote_filename =
|
|
141
|
+
temp_remote_filename = host.get_temp_filename()
|
|
140
142
|
|
|
141
143
|
# scp it to the temporary location
|
|
142
144
|
upload_cmd = "scp -P {0} {1} {2}:{3}".format(
|
|
@@ -149,7 +151,7 @@ def upload(
|
|
|
149
151
|
yield upload_cmd
|
|
150
152
|
|
|
151
153
|
# And sudo sudo to move it
|
|
152
|
-
yield from command(
|
|
154
|
+
yield from command._inner(
|
|
153
155
|
hostname=hostname,
|
|
154
156
|
command="sudo mv {0} {1}".format(temp_remote_filename, remote_filename),
|
|
155
157
|
port=port,
|
|
@@ -159,12 +161,12 @@ def upload(
|
|
|
159
161
|
|
|
160
162
|
@operation()
|
|
161
163
|
def download(
|
|
162
|
-
hostname,
|
|
163
|
-
filename,
|
|
164
|
-
local_filename=None,
|
|
164
|
+
hostname: str,
|
|
165
|
+
filename: str,
|
|
166
|
+
local_filename: str | None = None,
|
|
165
167
|
force=False,
|
|
166
168
|
port=22,
|
|
167
|
-
user=None,
|
|
169
|
+
user: str | None = None,
|
|
168
170
|
ssh_keyscan=False,
|
|
169
171
|
):
|
|
170
172
|
"""
|
|
@@ -203,7 +205,7 @@ def download(
|
|
|
203
205
|
connection_target = "@".join((user, hostname))
|
|
204
206
|
|
|
205
207
|
if ssh_keyscan:
|
|
206
|
-
yield from keyscan(hostname)
|
|
208
|
+
yield from keyscan._inner(hostname)
|
|
207
209
|
|
|
208
210
|
# Download the file with scp
|
|
209
211
|
yield "scp -P {0} {1}:{2} {3}".format(
|
pyinfra/operations/systemd.py
CHANGED
|
@@ -2,15 +2,19 @@
|
|
|
2
2
|
Manage systemd services.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import shlex
|
|
8
|
+
|
|
5
9
|
from pyinfra import host
|
|
6
|
-
from pyinfra.api import operation
|
|
10
|
+
from pyinfra.api import StringCommand, operation
|
|
7
11
|
from pyinfra.facts.systemd import SystemdEnabled, SystemdStatus, _make_systemctl_cmd
|
|
8
12
|
|
|
9
13
|
from .util.service import handle_service_control
|
|
10
14
|
|
|
11
15
|
|
|
12
16
|
@operation(is_idempotent=False)
|
|
13
|
-
def daemon_reload(user_mode=False, machine=None, user_name=None):
|
|
17
|
+
def daemon_reload(user_mode=False, machine: str | None = None, user_name: str | None = None):
|
|
14
18
|
"""
|
|
15
19
|
Reload the systemd daemon to read unit file changes.
|
|
16
20
|
|
|
@@ -25,24 +29,24 @@ def daemon_reload(user_mode=False, machine=None, user_name=None):
|
|
|
25
29
|
user_name=user_name,
|
|
26
30
|
)
|
|
27
31
|
|
|
28
|
-
yield "
|
|
32
|
+
yield StringCommand(systemctl_cmd, "daemon-reload")
|
|
29
33
|
|
|
30
34
|
|
|
31
|
-
_daemon_reload = daemon_reload # noqa: E305
|
|
35
|
+
_daemon_reload = daemon_reload._inner # noqa: E305
|
|
32
36
|
|
|
33
37
|
|
|
34
38
|
@operation()
|
|
35
39
|
def service(
|
|
36
|
-
service,
|
|
40
|
+
service: str,
|
|
37
41
|
running=True,
|
|
38
42
|
restarted=False,
|
|
39
43
|
reloaded=False,
|
|
40
|
-
command=None,
|
|
41
|
-
enabled=None,
|
|
44
|
+
command: str | None = None,
|
|
45
|
+
enabled: bool | None = None,
|
|
42
46
|
daemon_reload=False,
|
|
43
47
|
user_mode=False,
|
|
44
|
-
machine=None,
|
|
45
|
-
user_name=None,
|
|
48
|
+
machine: str | None = None,
|
|
49
|
+
user_name: str | None = None,
|
|
46
50
|
):
|
|
47
51
|
"""
|
|
48
52
|
Manage the state of systemd managed units.
|
|
@@ -117,8 +121,9 @@ def service(
|
|
|
117
121
|
user_mode=user_mode,
|
|
118
122
|
machine=machine,
|
|
119
123
|
user_name=user_name,
|
|
124
|
+
services=[service],
|
|
120
125
|
),
|
|
121
|
-
" ".join([systemctl_cmd, "{1}", "{0}"]),
|
|
126
|
+
" ".join([systemctl_cmd.get_raw_value(), "{1}", "{0}"]),
|
|
122
127
|
running,
|
|
123
128
|
restarted,
|
|
124
129
|
reloaded,
|
|
@@ -131,13 +136,14 @@ def service(
|
|
|
131
136
|
user_mode=user_mode,
|
|
132
137
|
machine=machine,
|
|
133
138
|
user_name=user_name,
|
|
139
|
+
services=[service],
|
|
134
140
|
)
|
|
135
141
|
is_enabled = systemd_enabled.get(service, False)
|
|
136
142
|
|
|
137
143
|
# Isn't enabled and want enabled?
|
|
138
144
|
if not is_enabled and enabled is True:
|
|
139
|
-
yield "{0} enable {1}".format(systemctl_cmd, service)
|
|
145
|
+
yield "{0} enable {1}".format(systemctl_cmd, shlex.quote(service))
|
|
140
146
|
|
|
141
147
|
# Is enabled and want disabled?
|
|
142
148
|
elif is_enabled and enabled is False:
|
|
143
|
-
yield "{0} disable {1}".format(systemctl_cmd, service)
|
|
149
|
+
yield "{0} disable {1}".format(systemctl_cmd, shlex.quote(service))
|
pyinfra/operations/sysvinit.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Manage sysvinit services (``/etc/init.d``).
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
5
7
|
from pyinfra import host
|
|
6
8
|
from pyinfra.api import operation
|
|
7
9
|
from pyinfra.facts.files import FindLinks
|
|
@@ -14,12 +16,12 @@ from .util.service import handle_service_control
|
|
|
14
16
|
|
|
15
17
|
@operation()
|
|
16
18
|
def service(
|
|
17
|
-
service,
|
|
19
|
+
service: str,
|
|
18
20
|
running=True,
|
|
19
21
|
restarted=False,
|
|
20
22
|
reloaded=False,
|
|
21
|
-
enabled=None,
|
|
22
|
-
command=None,
|
|
23
|
+
enabled: bool | None = None,
|
|
24
|
+
command: str | None = None,
|
|
23
25
|
):
|
|
24
26
|
"""
|
|
25
27
|
Manage the state of SysV Init (/etc/init.d) services.
|
|
@@ -95,7 +97,7 @@ def service(
|
|
|
95
97
|
|
|
96
98
|
@operation()
|
|
97
99
|
def enable(
|
|
98
|
-
service,
|
|
100
|
+
service: str,
|
|
99
101
|
start_priority=20,
|
|
100
102
|
stop_priority=80,
|
|
101
103
|
start_levels=(2, 3, 4, 5),
|
|
@@ -133,7 +135,7 @@ def enable(
|
|
|
133
135
|
|
|
134
136
|
# Ensure all the new links exist
|
|
135
137
|
for link in links:
|
|
136
|
-
yield from files.link(
|
|
138
|
+
yield from files.link._inner(
|
|
137
139
|
path=link,
|
|
138
140
|
target="/etc/init.d/{0}".format(service),
|
|
139
141
|
)
|
pyinfra/operations/upstart.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Manage upstart services.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
5
7
|
from io import StringIO
|
|
6
8
|
|
|
7
9
|
from pyinfra import host
|
|
@@ -14,12 +16,12 @@ from .util.service import handle_service_control
|
|
|
14
16
|
|
|
15
17
|
@operation()
|
|
16
18
|
def service(
|
|
17
|
-
service,
|
|
19
|
+
service: str,
|
|
18
20
|
running=True,
|
|
19
21
|
restarted=False,
|
|
20
22
|
reloaded=False,
|
|
21
|
-
command=None,
|
|
22
|
-
enabled=None,
|
|
23
|
+
command: str | None = None,
|
|
24
|
+
enabled: bool | None = None,
|
|
23
25
|
):
|
|
24
26
|
"""
|
|
25
27
|
Manage the state of upstart managed services.
|
|
@@ -52,7 +54,7 @@ def service(
|
|
|
52
54
|
# Upstart jobs are setup w/runlevels etc in their config files, so here we just check
|
|
53
55
|
# there's no override file.
|
|
54
56
|
if enabled is True:
|
|
55
|
-
yield from files.file(
|
|
57
|
+
yield from files.file._inner(
|
|
56
58
|
path="/etc/init/{0}.override".format(service),
|
|
57
59
|
present=False,
|
|
58
60
|
)
|
|
@@ -60,7 +62,7 @@ def service(
|
|
|
60
62
|
# Set the override file to "manual" to disable automatic start
|
|
61
63
|
elif enabled is False:
|
|
62
64
|
file = StringIO("manual\n")
|
|
63
|
-
yield from files.put(
|
|
65
|
+
yield from files.put._inner(
|
|
64
66
|
src=file,
|
|
65
67
|
dest="/etc/init/{0}.override".format(service),
|
|
66
68
|
)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Callable
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from pyinfra.api.operation import OperationMeta
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def any_changed(*args: "OperationMeta") -> Callable[[], bool]:
|
|
8
|
+
return lambda: any((meta.did_change() for meta in args))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def all_changed(*args: "OperationMeta") -> Callable[[], bool]:
|
|
12
|
+
return lambda: all((meta.did_change() for meta in args))
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
from pyinfra.api import OperationError
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def _create_container(**kwargs):
|
|
5
|
+
command = []
|
|
6
|
+
|
|
7
|
+
networks = kwargs["networks"] if kwargs["networks"] else []
|
|
8
|
+
ports = kwargs["ports"] if kwargs["ports"] else []
|
|
9
|
+
volumes = kwargs["volumes"] if kwargs["volumes"] else []
|
|
10
|
+
env_vars = kwargs["env_vars"] if kwargs["env_vars"] else []
|
|
11
|
+
|
|
12
|
+
if kwargs["image"] == "":
|
|
13
|
+
raise OperationError("missing 1 required argument: 'image'")
|
|
14
|
+
|
|
15
|
+
command.append("docker container create --name {0}".format(kwargs["container"]))
|
|
16
|
+
|
|
17
|
+
for network in networks:
|
|
18
|
+
command.append("--network {0}".format(network))
|
|
19
|
+
|
|
20
|
+
for port in ports:
|
|
21
|
+
command.append("-p {0}".format(port))
|
|
22
|
+
|
|
23
|
+
for volume in volumes:
|
|
24
|
+
command.append("-v {0}".format(volume))
|
|
25
|
+
|
|
26
|
+
for env_var in env_vars:
|
|
27
|
+
command.append("-e {0}".format(env_var))
|
|
28
|
+
|
|
29
|
+
if kwargs["pull_always"]:
|
|
30
|
+
command.append("--pull always")
|
|
31
|
+
|
|
32
|
+
command.append(kwargs["image"])
|
|
33
|
+
|
|
34
|
+
if kwargs["start"]:
|
|
35
|
+
command.append("; {0}".format(_start_container(container=kwargs["container"])))
|
|
36
|
+
|
|
37
|
+
return " ".join(command)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _remove_container(**kwargs):
|
|
41
|
+
return "docker container rm -f {0}".format(kwargs["container"])
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _start_container(**kwargs):
|
|
45
|
+
return "docker container start {0}".format(kwargs["container"])
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _stop_container(**kwargs):
|
|
49
|
+
return "docker container stop {0}".format(kwargs["container"])
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _pull_image(**kwargs):
|
|
53
|
+
return "docker image pull {0}".format(kwargs["image"])
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _remove_image(**kwargs):
|
|
57
|
+
return "docker image rm {0}".format(kwargs["image"])
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _prune_command(**kwargs):
|
|
61
|
+
command = ["docker system prune"]
|
|
62
|
+
|
|
63
|
+
if kwargs["all"]:
|
|
64
|
+
command.append("-a")
|
|
65
|
+
|
|
66
|
+
if kwargs["filter"] != "":
|
|
67
|
+
command.append("--filter={0}".format(kwargs["filter"]))
|
|
68
|
+
|
|
69
|
+
if kwargs["volumes"]:
|
|
70
|
+
command.append("--volumes")
|
|
71
|
+
|
|
72
|
+
command.append("-f")
|
|
73
|
+
|
|
74
|
+
return " ".join(command)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _create_volume(**kwargs):
|
|
78
|
+
command = []
|
|
79
|
+
labels = kwargs["labels"] if kwargs["labels"] else []
|
|
80
|
+
|
|
81
|
+
command.append("docker volume create {0}".format(kwargs["volume"]))
|
|
82
|
+
|
|
83
|
+
if kwargs["driver"] != "":
|
|
84
|
+
command.append("-d {0}".format(kwargs["driver"]))
|
|
85
|
+
|
|
86
|
+
for label in labels:
|
|
87
|
+
command.append("--label {0}".format(label))
|
|
88
|
+
|
|
89
|
+
return " ".join(command)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _remove_volume(**kwargs):
|
|
93
|
+
return "docker image rm {0}".format(kwargs["volume"])
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _create_network(**kwargs):
|
|
97
|
+
command = []
|
|
98
|
+
opts = kwargs["opts"] if kwargs["opts"] else []
|
|
99
|
+
ipam_opts = kwargs["ipam_opts"] if kwargs["ipam_opts"] else []
|
|
100
|
+
labels = kwargs["labels"] if kwargs["labels"] else []
|
|
101
|
+
|
|
102
|
+
command.append("docker network create {0}".format(kwargs["network"]))
|
|
103
|
+
if kwargs["driver"] != "":
|
|
104
|
+
command.append("-d {0}".format(kwargs["driver"]))
|
|
105
|
+
|
|
106
|
+
if kwargs["gateway"] != "":
|
|
107
|
+
command.append("--gateway {0}".format(kwargs["gateway"]))
|
|
108
|
+
|
|
109
|
+
if kwargs["ip_range"] != "":
|
|
110
|
+
command.append("--ip-range {0}".format(kwargs["ip_range"]))
|
|
111
|
+
|
|
112
|
+
if kwargs["ipam_driver"] != "":
|
|
113
|
+
command.append("--ipam-driver {0}".format(kwargs["ipam_driver"]))
|
|
114
|
+
|
|
115
|
+
if kwargs["subnet"] != "":
|
|
116
|
+
command.append("--subnet {0}".format(kwargs["subnet"]))
|
|
117
|
+
|
|
118
|
+
if kwargs["scope"] != "":
|
|
119
|
+
command.append("--scope {0}".format(kwargs["scope"]))
|
|
120
|
+
|
|
121
|
+
if kwargs["ingress"]:
|
|
122
|
+
command.append("--ingress")
|
|
123
|
+
|
|
124
|
+
if kwargs["attachable"]:
|
|
125
|
+
command.append("--attachable")
|
|
126
|
+
|
|
127
|
+
for opt in opts:
|
|
128
|
+
command.append("--opt {0}".format(opt))
|
|
129
|
+
|
|
130
|
+
for opt in ipam_opts:
|
|
131
|
+
command.append("--ipam-opt {0}".format(opt))
|
|
132
|
+
|
|
133
|
+
for label in labels:
|
|
134
|
+
command.append("--label {0}".format(label))
|
|
135
|
+
return " ".join(command)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _remove_network(**kwargs):
|
|
139
|
+
return "docker network rm {0}".format(kwargs["network"])
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def handle_docker(resource, command, **kwargs):
|
|
143
|
+
container_commands = {
|
|
144
|
+
"create": _create_container,
|
|
145
|
+
"remove": _remove_container,
|
|
146
|
+
"start": _start_container,
|
|
147
|
+
"stop": _stop_container,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
image_commands = {
|
|
151
|
+
"pull": _pull_image,
|
|
152
|
+
"remove": _remove_image,
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
volume_commands = {
|
|
156
|
+
"create": _create_volume,
|
|
157
|
+
"remove": _remove_volume,
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
network_commands = {
|
|
161
|
+
"create": _create_network,
|
|
162
|
+
"remove": _remove_network,
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
system_commands = {
|
|
166
|
+
"prune": _prune_command,
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
docker_commands = {
|
|
170
|
+
"container": container_commands,
|
|
171
|
+
"image": image_commands,
|
|
172
|
+
"volume": volume_commands,
|
|
173
|
+
"network": network_commands,
|
|
174
|
+
"system": system_commands,
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return docker_commands[resource][command](**kwargs)
|
pyinfra/operations/util/files.py
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import re
|
|
2
4
|
from datetime import datetime
|
|
3
5
|
|
|
4
6
|
from pyinfra.api import QuoteString, StringCommand
|
|
5
7
|
|
|
6
8
|
|
|
7
|
-
def unix_path_join(*
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return "/".join(
|
|
9
|
+
def unix_path_join(*parts) -> str:
|
|
10
|
+
part_list = list(parts)
|
|
11
|
+
part_list[0:-1] = [part.rstrip("/") for part in part_list[0:-1]]
|
|
12
|
+
return "/".join(part_list)
|
|
11
13
|
|
|
12
14
|
|
|
13
|
-
def ensure_mode_int(mode):
|
|
15
|
+
def ensure_mode_int(mode: str | int | None) -> int | str | None:
|
|
14
16
|
# Already an int (/None)?
|
|
15
17
|
if isinstance(mode, int) or mode is None:
|
|
16
18
|
return mode
|
|
@@ -26,19 +28,19 @@ def ensure_mode_int(mode):
|
|
|
26
28
|
return mode
|
|
27
29
|
|
|
28
30
|
|
|
29
|
-
def get_timestamp():
|
|
31
|
+
def get_timestamp() -> str:
|
|
30
32
|
return datetime.now().strftime("%y%m%d%H%M")
|
|
31
33
|
|
|
32
34
|
|
|
33
35
|
def sed_replace(
|
|
34
|
-
filename,
|
|
35
|
-
line,
|
|
36
|
-
replace,
|
|
37
|
-
flags=None,
|
|
36
|
+
filename: str,
|
|
37
|
+
line: str,
|
|
38
|
+
replace: str,
|
|
39
|
+
flags: list[str] | None = None,
|
|
38
40
|
backup=False,
|
|
39
41
|
interpolate_variables=False,
|
|
40
|
-
):
|
|
41
|
-
|
|
42
|
+
) -> StringCommand:
|
|
43
|
+
flags_str = "".join(flags) if flags else ""
|
|
42
44
|
|
|
43
45
|
line = line.replace("/", r"\/")
|
|
44
46
|
replace = str(replace)
|
|
@@ -57,7 +59,7 @@ def sed_replace(
|
|
|
57
59
|
replace = replace.replace("'", "'\"'\"'")
|
|
58
60
|
sed_script_formatter = "'s/{0}/{1}/{2}'"
|
|
59
61
|
|
|
60
|
-
sed_script = sed_script_formatter.format(line, replace,
|
|
62
|
+
sed_script = sed_script_formatter.format(line, replace, flags_str)
|
|
61
63
|
|
|
62
64
|
sed_command = StringCommand(
|
|
63
65
|
"sed",
|
|
@@ -73,7 +75,7 @@ def sed_replace(
|
|
|
73
75
|
return sed_command
|
|
74
76
|
|
|
75
77
|
|
|
76
|
-
def chmod(target, mode, recursive=False):
|
|
78
|
+
def chmod(target: str, mode: str | int, recursive=False) -> StringCommand:
|
|
77
79
|
args = ["chmod"]
|
|
78
80
|
if recursive:
|
|
79
81
|
args.append("-R")
|
|
@@ -83,7 +85,13 @@ def chmod(target, mode, recursive=False):
|
|
|
83
85
|
return StringCommand(" ".join(args), QuoteString(target))
|
|
84
86
|
|
|
85
87
|
|
|
86
|
-
def chown(
|
|
88
|
+
def chown(
|
|
89
|
+
target: str,
|
|
90
|
+
user: str | None = None,
|
|
91
|
+
group: str | None = None,
|
|
92
|
+
recursive=False,
|
|
93
|
+
dereference=True,
|
|
94
|
+
) -> StringCommand:
|
|
87
95
|
command = "chown"
|
|
88
96
|
user_group = None
|
|
89
97
|
|
|
@@ -107,7 +115,7 @@ def chown(target, user, group=None, recursive=False, dereference=True):
|
|
|
107
115
|
return StringCommand(" ".join(args), user_group, QuoteString(target))
|
|
108
116
|
|
|
109
117
|
|
|
110
|
-
def adjust_regex(line, escape_regex_characters):
|
|
118
|
+
def adjust_regex(line: str, escape_regex_characters: bool) -> str:
|
|
111
119
|
"""
|
|
112
120
|
Ensure the regex starts with '^' and ends with '$' and escape regex characters if requested
|
|
113
121
|
"""
|