pyinfra 0.11.dev3__py3-none-any.whl → 3.5.1__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/__init__.py +9 -12
- pyinfra/__main__.py +4 -0
- pyinfra/api/__init__.py +18 -3
- pyinfra/api/arguments.py +406 -0
- pyinfra/api/arguments_typed.py +79 -0
- pyinfra/api/command.py +274 -0
- pyinfra/api/config.py +222 -28
- pyinfra/api/connect.py +33 -13
- pyinfra/api/connectors.py +27 -0
- pyinfra/api/deploy.py +65 -66
- pyinfra/api/exceptions.py +67 -18
- pyinfra/api/facts.py +253 -202
- pyinfra/api/host.py +413 -50
- pyinfra/api/inventory.py +121 -160
- pyinfra/api/operation.py +432 -262
- pyinfra/api/operations.py +273 -260
- pyinfra/api/state.py +302 -248
- pyinfra/api/util.py +291 -368
- pyinfra/connectors/base.py +173 -0
- pyinfra/connectors/chroot.py +212 -0
- pyinfra/connectors/docker.py +381 -0
- pyinfra/connectors/dockerssh.py +297 -0
- pyinfra/connectors/local.py +238 -0
- pyinfra/connectors/scp/__init__.py +1 -0
- pyinfra/connectors/scp/client.py +204 -0
- pyinfra/connectors/ssh.py +670 -0
- pyinfra/connectors/ssh_util.py +114 -0
- pyinfra/connectors/sshuserclient/client.py +309 -0
- pyinfra/connectors/sshuserclient/config.py +102 -0
- pyinfra/connectors/terraform.py +135 -0
- pyinfra/connectors/util.py +410 -0
- pyinfra/connectors/vagrant.py +183 -0
- pyinfra/context.py +145 -0
- pyinfra/facts/__init__.py +7 -6
- pyinfra/facts/apk.py +22 -7
- pyinfra/facts/apt.py +117 -60
- pyinfra/facts/brew.py +100 -15
- pyinfra/facts/bsdinit.py +23 -0
- pyinfra/facts/cargo.py +37 -0
- pyinfra/facts/choco.py +47 -0
- pyinfra/facts/crontab.py +195 -0
- pyinfra/facts/deb.py +94 -0
- pyinfra/facts/dnf.py +48 -0
- pyinfra/facts/docker.py +96 -23
- pyinfra/facts/efibootmgr.py +113 -0
- pyinfra/facts/files.py +630 -58
- pyinfra/facts/flatpak.py +77 -0
- pyinfra/facts/freebsd.py +70 -0
- pyinfra/facts/gem.py +19 -6
- pyinfra/facts/git.py +59 -14
- pyinfra/facts/gpg.py +150 -0
- pyinfra/facts/hardware.py +313 -167
- pyinfra/facts/iptables.py +72 -62
- pyinfra/facts/launchd.py +44 -0
- pyinfra/facts/lxd.py +17 -4
- pyinfra/facts/mysql.py +122 -86
- pyinfra/facts/npm.py +17 -9
- pyinfra/facts/openrc.py +71 -0
- pyinfra/facts/opkg.py +246 -0
- pyinfra/facts/pacman.py +50 -7
- pyinfra/facts/pip.py +24 -7
- pyinfra/facts/pipx.py +82 -0
- pyinfra/facts/pkg.py +15 -6
- pyinfra/facts/pkgin.py +35 -0
- pyinfra/facts/podman.py +54 -0
- pyinfra/facts/postgres.py +178 -0
- pyinfra/facts/postgresql.py +6 -147
- pyinfra/facts/rpm.py +105 -0
- pyinfra/facts/runit.py +77 -0
- pyinfra/facts/selinux.py +161 -0
- pyinfra/facts/server.py +746 -285
- pyinfra/facts/snap.py +88 -0
- pyinfra/facts/systemd.py +139 -0
- pyinfra/facts/sysvinit.py +59 -0
- pyinfra/facts/upstart.py +35 -0
- pyinfra/facts/util/__init__.py +17 -0
- pyinfra/facts/util/databases.py +4 -6
- pyinfra/facts/util/packaging.py +37 -6
- pyinfra/facts/util/units.py +30 -0
- pyinfra/facts/util/win_files.py +99 -0
- pyinfra/facts/vzctl.py +20 -13
- pyinfra/facts/xbps.py +35 -0
- pyinfra/facts/yum.py +34 -40
- pyinfra/facts/zfs.py +77 -0
- pyinfra/facts/zypper.py +42 -0
- pyinfra/local.py +45 -83
- pyinfra/operations/__init__.py +12 -0
- pyinfra/operations/apk.py +98 -0
- pyinfra/operations/apt.py +488 -0
- pyinfra/operations/brew.py +231 -0
- pyinfra/operations/bsdinit.py +59 -0
- pyinfra/operations/cargo.py +45 -0
- pyinfra/operations/choco.py +61 -0
- pyinfra/operations/crontab.py +191 -0
- pyinfra/operations/dnf.py +210 -0
- pyinfra/operations/docker.py +446 -0
- pyinfra/operations/files.py +1939 -0
- pyinfra/operations/flatpak.py +94 -0
- pyinfra/operations/freebsd/__init__.py +12 -0
- pyinfra/operations/freebsd/freebsd_update.py +70 -0
- pyinfra/operations/freebsd/pkg.py +219 -0
- pyinfra/operations/freebsd/service.py +116 -0
- pyinfra/operations/freebsd/sysrc.py +92 -0
- pyinfra/operations/gem.py +47 -0
- pyinfra/operations/git.py +419 -0
- pyinfra/operations/iptables.py +311 -0
- pyinfra/operations/launchd.py +45 -0
- pyinfra/operations/lxd.py +68 -0
- pyinfra/operations/mysql.py +609 -0
- pyinfra/operations/npm.py +57 -0
- pyinfra/operations/openrc.py +63 -0
- pyinfra/operations/opkg.py +88 -0
- pyinfra/operations/pacman.py +81 -0
- pyinfra/operations/pip.py +205 -0
- pyinfra/operations/pipx.py +102 -0
- pyinfra/operations/pkg.py +70 -0
- pyinfra/operations/pkgin.py +91 -0
- pyinfra/operations/postgres.py +436 -0
- pyinfra/operations/postgresql.py +30 -0
- pyinfra/operations/puppet.py +40 -0
- pyinfra/operations/python.py +72 -0
- pyinfra/operations/runit.py +184 -0
- pyinfra/operations/selinux.py +189 -0
- pyinfra/operations/server.py +1099 -0
- pyinfra/operations/snap.py +117 -0
- pyinfra/operations/ssh.py +216 -0
- pyinfra/operations/systemd.py +149 -0
- pyinfra/operations/sysvinit.py +141 -0
- pyinfra/operations/upstart.py +68 -0
- pyinfra/operations/util/__init__.py +12 -0
- pyinfra/operations/util/docker.py +251 -0
- pyinfra/operations/util/files.py +247 -0
- pyinfra/operations/util/packaging.py +336 -0
- pyinfra/operations/util/service.py +46 -0
- pyinfra/operations/vzctl.py +137 -0
- pyinfra/operations/xbps.py +77 -0
- pyinfra/operations/yum.py +210 -0
- pyinfra/operations/zfs.py +175 -0
- pyinfra/operations/zypper.py +192 -0
- pyinfra/progress.py +44 -32
- pyinfra/py.typed +0 -0
- pyinfra/version.py +9 -1
- pyinfra-3.5.1.dist-info/METADATA +141 -0
- pyinfra-3.5.1.dist-info/RECORD +159 -0
- {pyinfra-0.11.dev3.dist-info → pyinfra-3.5.1.dist-info}/WHEEL +1 -2
- pyinfra-3.5.1.dist-info/entry_points.txt +12 -0
- {pyinfra-0.11.dev3.dist-info → pyinfra-3.5.1.dist-info/licenses}/LICENSE.md +1 -1
- pyinfra_cli/__init__.py +1 -0
- pyinfra_cli/cli.py +780 -0
- pyinfra_cli/commands.py +66 -0
- pyinfra_cli/exceptions.py +155 -65
- pyinfra_cli/inventory.py +233 -89
- pyinfra_cli/log.py +39 -43
- pyinfra_cli/main.py +26 -495
- pyinfra_cli/prints.py +215 -156
- pyinfra_cli/util.py +172 -105
- pyinfra_cli/virtualenv.py +25 -20
- pyinfra/api/connectors/__init__.py +0 -21
- pyinfra/api/connectors/ansible.py +0 -99
- pyinfra/api/connectors/docker.py +0 -178
- pyinfra/api/connectors/local.py +0 -169
- pyinfra/api/connectors/ssh.py +0 -402
- pyinfra/api/connectors/sshuserclient/client.py +0 -105
- pyinfra/api/connectors/sshuserclient/config.py +0 -90
- pyinfra/api/connectors/util.py +0 -63
- pyinfra/api/connectors/vagrant.py +0 -155
- pyinfra/facts/init.py +0 -176
- pyinfra/facts/util/files.py +0 -102
- pyinfra/hook.py +0 -41
- pyinfra/modules/__init__.py +0 -11
- pyinfra/modules/apk.py +0 -64
- pyinfra/modules/apt.py +0 -272
- pyinfra/modules/brew.py +0 -122
- pyinfra/modules/files.py +0 -711
- pyinfra/modules/gem.py +0 -30
- pyinfra/modules/git.py +0 -115
- pyinfra/modules/init.py +0 -344
- pyinfra/modules/iptables.py +0 -271
- pyinfra/modules/lxd.py +0 -45
- pyinfra/modules/mysql.py +0 -347
- pyinfra/modules/npm.py +0 -47
- pyinfra/modules/pacman.py +0 -60
- pyinfra/modules/pip.py +0 -99
- pyinfra/modules/pkg.py +0 -43
- pyinfra/modules/postgresql.py +0 -245
- pyinfra/modules/puppet.py +0 -20
- pyinfra/modules/python.py +0 -37
- pyinfra/modules/server.py +0 -524
- pyinfra/modules/ssh.py +0 -150
- pyinfra/modules/util/files.py +0 -52
- pyinfra/modules/util/packaging.py +0 -118
- pyinfra/modules/vzctl.py +0 -133
- pyinfra/modules/yum.py +0 -171
- pyinfra/pseudo_modules.py +0 -64
- pyinfra-0.11.dev3.dist-info/.DS_Store +0 -0
- pyinfra-0.11.dev3.dist-info/METADATA +0 -135
- pyinfra-0.11.dev3.dist-info/RECORD +0 -95
- pyinfra-0.11.dev3.dist-info/entry_points.txt +0 -3
- pyinfra-0.11.dev3.dist-info/top_level.txt +0 -2
- pyinfra_cli/__main__.py +0 -40
- pyinfra_cli/config.py +0 -92
- /pyinfra/{modules/util → connectors}/__init__.py +0 -0
- /pyinfra/{api/connectors → connectors}/sshuserclient/__init__.py +0 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import abc
|
|
4
|
+
from io import IOBase
|
|
5
|
+
from typing import (
|
|
6
|
+
TYPE_CHECKING,
|
|
7
|
+
Any,
|
|
8
|
+
Iterable,
|
|
9
|
+
Iterator,
|
|
10
|
+
Optional,
|
|
11
|
+
Type,
|
|
12
|
+
TypeVar,
|
|
13
|
+
Union,
|
|
14
|
+
cast,
|
|
15
|
+
get_type_hints,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from typing_extensions import TypedDict, Unpack
|
|
19
|
+
|
|
20
|
+
from pyinfra.api.exceptions import ConnectorDataTypeError
|
|
21
|
+
from pyinfra.api.util import raise_if_bad_type
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from pyinfra.api.arguments import ConnectorArguments
|
|
25
|
+
from pyinfra.api.command import StringCommand
|
|
26
|
+
from pyinfra.api.host import Host, HostData
|
|
27
|
+
from pyinfra.api.state import State
|
|
28
|
+
|
|
29
|
+
from .util import CommandOutput
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
T = TypeVar("T")
|
|
33
|
+
default_sentinel = object()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def host_to_connector_data(
|
|
37
|
+
connector_data: Type[T],
|
|
38
|
+
connector_data_meta: dict[str, DataMeta],
|
|
39
|
+
host_data: "HostData",
|
|
40
|
+
) -> T:
|
|
41
|
+
data: T = cast(T, {})
|
|
42
|
+
for key, type_ in get_type_hints(connector_data).items():
|
|
43
|
+
value = host_data.get(key, default_sentinel)
|
|
44
|
+
if value is default_sentinel:
|
|
45
|
+
value = connector_data_meta[key].default
|
|
46
|
+
else:
|
|
47
|
+
raise_if_bad_type(
|
|
48
|
+
value,
|
|
49
|
+
type_,
|
|
50
|
+
ConnectorDataTypeError,
|
|
51
|
+
f"Invalid connector data `{key}`:",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
data[key] = value # type: ignore
|
|
55
|
+
return data
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class DataMeta:
|
|
59
|
+
description: str
|
|
60
|
+
default: Any
|
|
61
|
+
|
|
62
|
+
def __init__(self, description, default=None) -> None:
|
|
63
|
+
self.description = description
|
|
64
|
+
self.default = default
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ConnectorData(TypedDict, total=False):
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class BaseConnector(abc.ABC):
|
|
72
|
+
state: "State"
|
|
73
|
+
host: "Host"
|
|
74
|
+
|
|
75
|
+
handles_execution = False
|
|
76
|
+
|
|
77
|
+
data_cls: Type = ConnectorData
|
|
78
|
+
data_meta: dict[str, DataMeta] = {}
|
|
79
|
+
|
|
80
|
+
def __init__(self, state: "State", host: "Host"):
|
|
81
|
+
self.state = state
|
|
82
|
+
self.host = host
|
|
83
|
+
self.data = host_to_connector_data(self.data_cls, self.data_meta, host.data)
|
|
84
|
+
|
|
85
|
+
@staticmethod
|
|
86
|
+
@abc.abstractmethod
|
|
87
|
+
def make_names_data(name: str) -> Iterator[tuple[str, dict, list[str]]]:
|
|
88
|
+
"""
|
|
89
|
+
Generate inventory targets. This is a staticmethod because each yield will become a new host
|
|
90
|
+
object with a new (ie not this) instance of the connector.
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
def connect(self) -> None:
|
|
94
|
+
"""
|
|
95
|
+
Connect this connector instance. Should raise ConnectError exceptions to indicate failure.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
def disconnect(self) -> None:
|
|
99
|
+
"""
|
|
100
|
+
Disconnect this connector instance.
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
@abc.abstractmethod
|
|
104
|
+
def run_shell_command(
|
|
105
|
+
self,
|
|
106
|
+
command: "StringCommand",
|
|
107
|
+
print_output: bool,
|
|
108
|
+
print_input: bool,
|
|
109
|
+
**arguments: Unpack["ConnectorArguments"],
|
|
110
|
+
) -> tuple[bool, "CommandOutput"]:
|
|
111
|
+
"""
|
|
112
|
+
Execute a command.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
command (StringCommand): actual command to execute
|
|
116
|
+
print_output (bool): whether to print command output
|
|
117
|
+
print_input (bool): whether to print command input
|
|
118
|
+
arguments: (ConnectorArguments): connector global arguments
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
tuple: (bool, CommandOutput)
|
|
122
|
+
Bool indicating success and CommandOutput with stdout/stderr lines.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
@abc.abstractmethod
|
|
126
|
+
def put_file(
|
|
127
|
+
self,
|
|
128
|
+
filename_or_io: Union[str, IOBase],
|
|
129
|
+
remote_filename: str,
|
|
130
|
+
remote_temp_filename: Optional[str] = None,
|
|
131
|
+
print_output: bool = False,
|
|
132
|
+
print_input: bool = False,
|
|
133
|
+
**arguments: Unpack["ConnectorArguments"],
|
|
134
|
+
) -> bool:
|
|
135
|
+
"""
|
|
136
|
+
Upload a local file or IO object by copying it to a temporary directory
|
|
137
|
+
and then writing it to the upload location.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
bool: indicating success or failure.
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
@abc.abstractmethod
|
|
144
|
+
def get_file(
|
|
145
|
+
self,
|
|
146
|
+
remote_filename: str,
|
|
147
|
+
filename_or_io: Union[str, IOBase],
|
|
148
|
+
remote_temp_filename: Optional[str] = None,
|
|
149
|
+
print_output: bool = False,
|
|
150
|
+
print_input: bool = False,
|
|
151
|
+
**arguments: Unpack["ConnectorArguments"],
|
|
152
|
+
) -> bool:
|
|
153
|
+
"""
|
|
154
|
+
Download a local file by copying it to a temporary location and then writing
|
|
155
|
+
it to our filename or IO object.
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
bool: indicating success or failure.
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
def check_can_rsync(self) -> None:
|
|
162
|
+
raise NotImplementedError("This connector does not support rsync")
|
|
163
|
+
|
|
164
|
+
def rsync(
|
|
165
|
+
self,
|
|
166
|
+
src: str,
|
|
167
|
+
dest: str,
|
|
168
|
+
flags: Iterable[str],
|
|
169
|
+
print_output: bool = False,
|
|
170
|
+
print_input: bool = False,
|
|
171
|
+
**arguments: Unpack["ConnectorArguments"],
|
|
172
|
+
) -> bool:
|
|
173
|
+
raise NotImplementedError("This connector does not support rsync")
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from tempfile import mkstemp
|
|
3
|
+
from typing import TYPE_CHECKING, Optional
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
from typing_extensions import Unpack, override
|
|
7
|
+
|
|
8
|
+
from pyinfra import local, logger
|
|
9
|
+
from pyinfra.api import QuoteString, StringCommand
|
|
10
|
+
from pyinfra.api.exceptions import ConnectError, InventoryError, PyinfraError
|
|
11
|
+
from pyinfra.api.util import get_file_io, memoize
|
|
12
|
+
from pyinfra.progress import progress_spinner
|
|
13
|
+
|
|
14
|
+
from .base import BaseConnector
|
|
15
|
+
from .local import LocalConnector
|
|
16
|
+
from .util import extract_control_arguments, make_unix_command_for_host
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from pyinfra.api.arguments import ConnectorArguments
|
|
20
|
+
from pyinfra.api.host import Host
|
|
21
|
+
from pyinfra.api.state import State
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@memoize
|
|
25
|
+
def show_warning() -> None:
|
|
26
|
+
logger.warning("The @chroot connector is in beta!")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ChrootConnector(BaseConnector):
|
|
30
|
+
"""
|
|
31
|
+
The chroot connector allows you to execute operations within another root.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
handles_execution = True
|
|
35
|
+
|
|
36
|
+
local: LocalConnector
|
|
37
|
+
|
|
38
|
+
def __init__(self, state: "State", host: "Host"):
|
|
39
|
+
super().__init__(state, host)
|
|
40
|
+
self.local = LocalConnector(state, host)
|
|
41
|
+
|
|
42
|
+
@override
|
|
43
|
+
@staticmethod
|
|
44
|
+
def make_names_data(name: Optional[str] = None):
|
|
45
|
+
if not name:
|
|
46
|
+
raise InventoryError("No directory provided!")
|
|
47
|
+
|
|
48
|
+
show_warning()
|
|
49
|
+
|
|
50
|
+
yield (
|
|
51
|
+
"@chroot/{0}".format(name),
|
|
52
|
+
{
|
|
53
|
+
"chroot_directory": "/{0}".format(name.lstrip("/")),
|
|
54
|
+
},
|
|
55
|
+
["@chroot"],
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
@override
|
|
59
|
+
def connect(self) -> None:
|
|
60
|
+
self.local.connect()
|
|
61
|
+
|
|
62
|
+
chroot_directory = self.host.data.chroot_directory
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
with progress_spinner({"chroot run"}):
|
|
66
|
+
local.shell(
|
|
67
|
+
"chroot {0} ls".format(chroot_directory),
|
|
68
|
+
splitlines=True,
|
|
69
|
+
)
|
|
70
|
+
except PyinfraError as e:
|
|
71
|
+
raise ConnectError(e.args[0])
|
|
72
|
+
|
|
73
|
+
self.host.connector_data["chroot_directory"] = chroot_directory
|
|
74
|
+
|
|
75
|
+
@override
|
|
76
|
+
def run_shell_command(
|
|
77
|
+
self,
|
|
78
|
+
command,
|
|
79
|
+
print_output: bool = False,
|
|
80
|
+
print_input: bool = False,
|
|
81
|
+
**command_arguments: Unpack["ConnectorArguments"],
|
|
82
|
+
):
|
|
83
|
+
local_arguments = extract_control_arguments(command_arguments)
|
|
84
|
+
|
|
85
|
+
chroot_directory = self.host.connector_data["chroot_directory"]
|
|
86
|
+
|
|
87
|
+
command = make_unix_command_for_host(self.state, self.host, command, **command_arguments)
|
|
88
|
+
command = QuoteString(command)
|
|
89
|
+
|
|
90
|
+
logger.debug("--> Running chroot command on (%s): %s", chroot_directory, command)
|
|
91
|
+
|
|
92
|
+
chroot_command = StringCommand(
|
|
93
|
+
"chroot",
|
|
94
|
+
chroot_directory,
|
|
95
|
+
"sh",
|
|
96
|
+
"-c",
|
|
97
|
+
command,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
return self.local.run_shell_command(
|
|
101
|
+
chroot_command,
|
|
102
|
+
print_output=print_output,
|
|
103
|
+
print_input=print_input,
|
|
104
|
+
**local_arguments,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
@override
|
|
108
|
+
def put_file(
|
|
109
|
+
self,
|
|
110
|
+
filename_or_io,
|
|
111
|
+
remote_filename,
|
|
112
|
+
remote_temp_filename=None, # ignored
|
|
113
|
+
print_output: bool = False,
|
|
114
|
+
print_input: bool = False,
|
|
115
|
+
**kwargs, # ignored (sudo/etc)
|
|
116
|
+
):
|
|
117
|
+
_, temp_filename = mkstemp()
|
|
118
|
+
|
|
119
|
+
try:
|
|
120
|
+
# Load our file or IO object and write it to the temporary file
|
|
121
|
+
with get_file_io(filename_or_io) as file_io:
|
|
122
|
+
with open(temp_filename, "wb") as temp_f:
|
|
123
|
+
data = file_io.read()
|
|
124
|
+
|
|
125
|
+
if isinstance(data, str):
|
|
126
|
+
data = data.encode()
|
|
127
|
+
|
|
128
|
+
temp_f.write(data)
|
|
129
|
+
|
|
130
|
+
chroot_directory = self.host.connector_data["chroot_directory"]
|
|
131
|
+
chroot_command = StringCommand(
|
|
132
|
+
"cp",
|
|
133
|
+
temp_filename,
|
|
134
|
+
f"{chroot_directory}/{remote_filename}",
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
status, output = self.local.run_shell_command(
|
|
138
|
+
chroot_command,
|
|
139
|
+
print_output=print_output,
|
|
140
|
+
print_input=print_input,
|
|
141
|
+
)
|
|
142
|
+
finally:
|
|
143
|
+
os.remove(temp_filename)
|
|
144
|
+
|
|
145
|
+
if not status:
|
|
146
|
+
raise IOError(output.stderr)
|
|
147
|
+
|
|
148
|
+
if print_output:
|
|
149
|
+
click.echo(
|
|
150
|
+
"{0}file uploaded to chroot: {1}".format(
|
|
151
|
+
self.host.print_prefix,
|
|
152
|
+
remote_filename,
|
|
153
|
+
),
|
|
154
|
+
err=True,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
return status
|
|
158
|
+
|
|
159
|
+
@override
|
|
160
|
+
def get_file(
|
|
161
|
+
self,
|
|
162
|
+
remote_filename,
|
|
163
|
+
filename_or_io,
|
|
164
|
+
remote_temp_filename=None, # ignored
|
|
165
|
+
print_output: bool = False,
|
|
166
|
+
print_input: bool = False,
|
|
167
|
+
**kwargs, # ignored (sudo/etc)
|
|
168
|
+
):
|
|
169
|
+
_, temp_filename = mkstemp()
|
|
170
|
+
|
|
171
|
+
try:
|
|
172
|
+
chroot_directory = self.host.connector_data["chroot_directory"]
|
|
173
|
+
chroot_command = StringCommand(
|
|
174
|
+
"cp",
|
|
175
|
+
f"{chroot_directory}/{remote_filename}",
|
|
176
|
+
temp_filename,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
status, output = self.local.run_shell_command(
|
|
180
|
+
chroot_command,
|
|
181
|
+
print_output=print_output,
|
|
182
|
+
print_input=print_input,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# Load the temporary file and write it to our file or IO object
|
|
186
|
+
with open(temp_filename, "rb") as temp_f:
|
|
187
|
+
with get_file_io(filename_or_io, "wb") as file_io:
|
|
188
|
+
data = temp_f.read()
|
|
189
|
+
data_bytes: bytes
|
|
190
|
+
|
|
191
|
+
if isinstance(data, str):
|
|
192
|
+
data_bytes = data.encode()
|
|
193
|
+
else:
|
|
194
|
+
data_bytes = data
|
|
195
|
+
|
|
196
|
+
file_io.write(data_bytes)
|
|
197
|
+
finally:
|
|
198
|
+
os.remove(temp_filename)
|
|
199
|
+
|
|
200
|
+
if not status:
|
|
201
|
+
raise IOError(output.stderr)
|
|
202
|
+
|
|
203
|
+
if print_output:
|
|
204
|
+
click.echo(
|
|
205
|
+
"{0}file downloaded from chroot: {1}".format(
|
|
206
|
+
self.host.print_prefix,
|
|
207
|
+
remote_filename,
|
|
208
|
+
),
|
|
209
|
+
err=True,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
return status
|