scalebox-sdk 0.1.4__py3-none-any.whl → 0.1.25__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.
- scalebox/__init__.py +1 -1
- scalebox/api/__init__.py +128 -128
- scalebox/api/client/__init__.py +8 -8
- scalebox/api/client/api/sandboxes/get_sandboxes.py +5 -3
- scalebox/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py +2 -2
- scalebox/api/client/api/sandboxes/post_sandboxes.py +2 -2
- scalebox/api/client/client.py +288 -288
- scalebox/api/client/models/listed_sandbox.py +11 -9
- scalebox/api/client/models/new_sandbox.py +1 -1
- scalebox/api/client/models/sandbox.py +125 -125
- scalebox/api/client/models/sandbox_state.py +1 -0
- scalebox/api/client/types.py +46 -46
- scalebox/code_interpreter/code_interpreter_async.py +370 -369
- scalebox/code_interpreter/code_interpreter_sync.py +318 -317
- scalebox/connection_config.py +92 -92
- scalebox/csx_desktop/main.py +12 -12
- scalebox/generated/api_pb2_connect.py +17 -66
- scalebox/sandbox_async/commands/command.py +307 -307
- scalebox/sandbox_async/commands/command_handle.py +187 -187
- scalebox/sandbox_async/commands/pty.py +187 -187
- scalebox/sandbox_async/filesystem/filesystem.py +557 -557
- scalebox/sandbox_async/filesystem/watch_handle.py +61 -61
- scalebox/sandbox_async/main.py +647 -646
- scalebox/sandbox_async/sandbox_api.py +365 -365
- scalebox/sandbox_async/utils.py +7 -7
- scalebox/sandbox_sync/__init__.py +2 -2
- scalebox/sandbox_sync/commands/command.py +300 -300
- scalebox/sandbox_sync/commands/command_handle.py +150 -150
- scalebox/sandbox_sync/commands/pty.py +181 -181
- scalebox/sandbox_sync/filesystem/filesystem.py +543 -543
- scalebox/sandbox_sync/filesystem/watch_handle.py +66 -66
- scalebox/sandbox_sync/main.py +789 -790
- scalebox/sandbox_sync/sandbox_api.py +356 -356
- scalebox/test/CODE_INTERPRETER_TESTS_READY.md +256 -256
- scalebox/test/README.md +164 -164
- scalebox/test/aclient.py +72 -72
- scalebox/test/code_interpreter_centext.py +21 -21
- scalebox/test/code_interpreter_centext_sync.py +21 -21
- scalebox/test/code_interpreter_test.py +1 -1
- scalebox/test/code_interpreter_test_sync.py +1 -1
- scalebox/test/run_all_validation_tests.py +334 -334
- scalebox/test/test_basic.py +78 -78
- scalebox/test/test_code_interpreter_async_comprehensive.py +2653 -2653
- scalebox/test/{test_code_interpreter_e2bsync_comprehensive.py → test_code_interpreter_execcode.py} +328 -392
- scalebox/test/test_code_interpreter_sync_comprehensive.py +3416 -3412
- scalebox/test/test_csx_desktop_examples.py +130 -0
- scalebox/test/test_sandbox_async_comprehensive.py +736 -738
- scalebox/test/test_sandbox_stress_and_edge_cases.py +778 -778
- scalebox/test/test_sandbox_sync_comprehensive.py +779 -770
- scalebox/test/test_sandbox_usage_examples.py +987 -987
- scalebox/test/testacreate.py +24 -24
- scalebox/test/testagetinfo.py +18 -18
- scalebox/test/testcodeinterpreter_async.py +508 -508
- scalebox/test/testcodeinterpreter_sync.py +239 -239
- scalebox/test/testcomputeuse.py +2 -2
- scalebox/test/testnovnc.py +12 -12
- scalebox/test/testsandbox_api.py +15 -0
- scalebox/test/testsandbox_async.py +202 -118
- scalebox/test/testsandbox_sync.py +71 -38
- scalebox/version.py +2 -2
- {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/METADATA +104 -103
- {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/RECORD +66 -66
- scalebox/test/test_code_interpreter_e2basync_comprehensive.py +0 -2655
- scalebox/test/test_e2b_first.py +0 -11
- {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/WHEEL +0 -0
- {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/entry_points.txt +0 -0
- {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/licenses/LICENSE +0 -0
- {scalebox_sdk-0.1.4.dist-info → scalebox_sdk-0.1.25.dist-info}/top_level.txt +0 -0
scalebox/sandbox_async/utils.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from typing import Awaitable, Callable, TypeVar, Union
|
|
2
|
-
|
|
3
|
-
T = TypeVar("T")
|
|
4
|
-
OutputHandler = Union[
|
|
5
|
-
Callable[[T], None],
|
|
6
|
-
Callable[[T], Awaitable[None]],
|
|
7
|
-
]
|
|
1
|
+
from typing import Awaitable, Callable, TypeVar, Union
|
|
2
|
+
|
|
3
|
+
T = TypeVar("T")
|
|
4
|
+
OutputHandler = Union[
|
|
5
|
+
Callable[[T], None],
|
|
6
|
+
Callable[[T], Awaitable[None]],
|
|
7
|
+
]
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
from .commands.command_handle import CommandExitException, CommandHandle, CommandResult
|
|
2
|
-
from .main import Sandbox
|
|
1
|
+
from .commands.command_handle import CommandExitException, CommandHandle, CommandResult
|
|
2
|
+
from .main import Sandbox
|
|
@@ -1,300 +1,300 @@
|
|
|
1
|
-
from typing import Callable, Dict, List, Literal, Optional, Union, overload
|
|
2
|
-
|
|
3
|
-
import httpcore
|
|
4
|
-
import urllib3
|
|
5
|
-
|
|
6
|
-
from ... import csx_connect
|
|
7
|
-
from ...connection_config import (
|
|
8
|
-
KEEPALIVE_PING_HEADER,
|
|
9
|
-
KEEPALIVE_PING_INTERVAL_SEC,
|
|
10
|
-
ConnectionConfig,
|
|
11
|
-
Username,
|
|
12
|
-
)
|
|
13
|
-
from ...exceptions import SandboxException
|
|
14
|
-
from ...generated import api_pb2, api_pb2_connect
|
|
15
|
-
from ...generated.rpc import authentication_header, handle_rpc_exception
|
|
16
|
-
from ...sandbox.commands.command_handle import CommandResult
|
|
17
|
-
from ...sandbox.commands.main import ProcessInfo
|
|
18
|
-
from ...sandbox_sync.commands.command_handle import CommandHandle
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class Commands:
|
|
22
|
-
"""
|
|
23
|
-
Module for executing commands in the sandbox.
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
def __init__(
|
|
27
|
-
self,
|
|
28
|
-
envd_api_url: str,
|
|
29
|
-
connection_config: ConnectionConfig,
|
|
30
|
-
pool: urllib3.PoolManager,
|
|
31
|
-
) -> None:
|
|
32
|
-
self._connection_config = connection_config
|
|
33
|
-
self._rpc = api_pb2_connect.ProcessClient(
|
|
34
|
-
envd_api_url,
|
|
35
|
-
http_client=pool,
|
|
36
|
-
)
|
|
37
|
-
self._headers = connection_config.headers
|
|
38
|
-
self._pool = pool
|
|
39
|
-
|
|
40
|
-
def list(
|
|
41
|
-
self,
|
|
42
|
-
request_timeout: Optional[float] = None,
|
|
43
|
-
) -> List[ProcessInfo]:
|
|
44
|
-
"""
|
|
45
|
-
Lists all running commands and PTY sessions.
|
|
46
|
-
|
|
47
|
-
:param request_timeout: Timeout for the request in **seconds**
|
|
48
|
-
|
|
49
|
-
:return: List of running commands and PTY sessions
|
|
50
|
-
"""
|
|
51
|
-
try:
|
|
52
|
-
res = self._rpc.list(
|
|
53
|
-
api_pb2.ListRequest(),
|
|
54
|
-
self._headers,
|
|
55
|
-
timeout_seconds=self._connection_config.get_request_timeout(
|
|
56
|
-
request_timeout
|
|
57
|
-
),
|
|
58
|
-
)
|
|
59
|
-
return [
|
|
60
|
-
ProcessInfo(
|
|
61
|
-
pid=p.pid,
|
|
62
|
-
tag=p.tag,
|
|
63
|
-
cmd=p.config.cmd,
|
|
64
|
-
args=list(p.config.args),
|
|
65
|
-
envs=dict(p.config.envs),
|
|
66
|
-
cwd=p.config.cwd,
|
|
67
|
-
)
|
|
68
|
-
for p in res.processes
|
|
69
|
-
]
|
|
70
|
-
except Exception as e:
|
|
71
|
-
raise handle_rpc_exception(e)
|
|
72
|
-
|
|
73
|
-
def kill(
|
|
74
|
-
self,
|
|
75
|
-
pid: int,
|
|
76
|
-
request_timeout: Optional[float] = None,
|
|
77
|
-
) -> bool:
|
|
78
|
-
"""
|
|
79
|
-
Kills a running command specified by its process ID.
|
|
80
|
-
It uses `SIGKILL` signal to kill the command.
|
|
81
|
-
|
|
82
|
-
:param pid: Process ID of the command. You can get the list of processes using `sandbox.commands.list()`
|
|
83
|
-
:param request_timeout: Timeout for the request in **seconds**
|
|
84
|
-
|
|
85
|
-
:return: `True` if the command was killed, `False` if the command was not found
|
|
86
|
-
"""
|
|
87
|
-
try:
|
|
88
|
-
self._rpc.send_signal(
|
|
89
|
-
api_pb2.SendSignalRequest(
|
|
90
|
-
process=api_pb2.ProcessSelector(pid=pid),
|
|
91
|
-
signal=api_pb2.Signal.SIGNAL_SIGKILL,
|
|
92
|
-
),
|
|
93
|
-
self._headers,
|
|
94
|
-
timeout_seconds=self._connection_config.get_request_timeout(
|
|
95
|
-
request_timeout
|
|
96
|
-
),
|
|
97
|
-
)
|
|
98
|
-
return True
|
|
99
|
-
except Exception as e:
|
|
100
|
-
if "not found" in str(e):
|
|
101
|
-
return False
|
|
102
|
-
raise handle_rpc_exception(e)
|
|
103
|
-
|
|
104
|
-
def send_stdin(
|
|
105
|
-
self,
|
|
106
|
-
pid: int,
|
|
107
|
-
data: str,
|
|
108
|
-
request_timeout: Optional[float] = None,
|
|
109
|
-
):
|
|
110
|
-
"""
|
|
111
|
-
Send data to command stdin.
|
|
112
|
-
|
|
113
|
-
:param pid Process ID of the command. You can get the list of processes using `sandbox.commands.list()`.
|
|
114
|
-
:param data: Data to send to the command
|
|
115
|
-
:param request_timeout: Timeout for the request in **seconds**
|
|
116
|
-
"""
|
|
117
|
-
try:
|
|
118
|
-
self._rpc.send_input(
|
|
119
|
-
api_pb2.SendInputRequest(
|
|
120
|
-
process=api_pb2.ProcessSelector(pid=pid),
|
|
121
|
-
input=api_pb2.ProcessInput(
|
|
122
|
-
stdin=data.encode(),
|
|
123
|
-
),
|
|
124
|
-
),
|
|
125
|
-
self._headers,
|
|
126
|
-
timeout_seconds=self._connection_config.get_request_timeout(
|
|
127
|
-
request_timeout
|
|
128
|
-
),
|
|
129
|
-
)
|
|
130
|
-
except Exception as e:
|
|
131
|
-
raise handle_rpc_exception(e)
|
|
132
|
-
|
|
133
|
-
@overload
|
|
134
|
-
def run(
|
|
135
|
-
self,
|
|
136
|
-
cmd: str,
|
|
137
|
-
background: Union[Literal[False], None] = None,
|
|
138
|
-
envs: Optional[Dict[str, str]] = None,
|
|
139
|
-
user: Username = "user",
|
|
140
|
-
cwd: Optional[str] = None,
|
|
141
|
-
on_stdout: Optional[Callable[[str], None]] = None,
|
|
142
|
-
on_stderr: Optional[Callable[[str], None]] = None,
|
|
143
|
-
timeout: Optional[float] = 60,
|
|
144
|
-
request_timeout: Optional[float] = None,
|
|
145
|
-
) -> CommandResult:
|
|
146
|
-
"""
|
|
147
|
-
Start a new command and wait until it finishes executing.
|
|
148
|
-
|
|
149
|
-
:param cmd: Command to execute
|
|
150
|
-
:param background: **`False` if the command should be executed in the foreground**, `True` if the command should be executed in the background
|
|
151
|
-
:param envs: Environment variables used for the command
|
|
152
|
-
:param user: User to run the command as
|
|
153
|
-
:param cwd: Working directory to run the command
|
|
154
|
-
:param on_stdout: Callback for command stdout output
|
|
155
|
-
:param on_stderr: Callback for command stderr output
|
|
156
|
-
:param timeout: Timeout for the command connection in **seconds**. Using `0` will not limit the command connection time
|
|
157
|
-
:param request_timeout: Timeout for the request in **seconds**
|
|
158
|
-
|
|
159
|
-
:return: `CommandResult` result of the command execution
|
|
160
|
-
"""
|
|
161
|
-
...
|
|
162
|
-
|
|
163
|
-
@overload
|
|
164
|
-
def run(
|
|
165
|
-
self,
|
|
166
|
-
cmd: str,
|
|
167
|
-
background: Literal[True],
|
|
168
|
-
envs: Optional[Dict[str, str]] = None,
|
|
169
|
-
user: Username = "user",
|
|
170
|
-
cwd: Optional[str] = None,
|
|
171
|
-
on_stdout: None = None,
|
|
172
|
-
on_stderr: None = None,
|
|
173
|
-
timeout: Optional[float] = 60,
|
|
174
|
-
request_timeout: Optional[float] = None,
|
|
175
|
-
) -> CommandHandle:
|
|
176
|
-
"""
|
|
177
|
-
Start a new command and return a handle to interact with it.
|
|
178
|
-
|
|
179
|
-
:param cmd: Command to execute
|
|
180
|
-
:param background: `False` if the command should be executed in the foreground, **`True` if the command should be executed in the background**
|
|
181
|
-
:param envs: Environment variables used for the command
|
|
182
|
-
:param user: User to run the command as
|
|
183
|
-
:param cwd: Working directory to run the command
|
|
184
|
-
:param timeout: Timeout for the command connection in **seconds**. Using `0` will not limit the command connection time
|
|
185
|
-
:param request_timeout: Timeout for the request in **seconds**
|
|
186
|
-
|
|
187
|
-
:return: `CommandHandle` handle to interact with the running command
|
|
188
|
-
"""
|
|
189
|
-
...
|
|
190
|
-
|
|
191
|
-
def run(
|
|
192
|
-
self,
|
|
193
|
-
cmd: str,
|
|
194
|
-
background: Union[bool, None] = None,
|
|
195
|
-
envs: Optional[Dict[str, str]] = None,
|
|
196
|
-
user: Username = "user",
|
|
197
|
-
cwd: Optional[str] = None,
|
|
198
|
-
on_stdout: Optional[Callable[[str], None]] = None,
|
|
199
|
-
on_stderr: Optional[Callable[[str], None]] = None,
|
|
200
|
-
timeout: Optional[float] = 60,
|
|
201
|
-
request_timeout: Optional[float] = None,
|
|
202
|
-
):
|
|
203
|
-
if background:
|
|
204
|
-
cmd += " &"
|
|
205
|
-
proc = self._start(
|
|
206
|
-
cmd,
|
|
207
|
-
envs,
|
|
208
|
-
user,
|
|
209
|
-
cwd,
|
|
210
|
-
timeout,
|
|
211
|
-
request_timeout,
|
|
212
|
-
)
|
|
213
|
-
|
|
214
|
-
return (
|
|
215
|
-
proc
|
|
216
|
-
if background
|
|
217
|
-
else proc.wait(
|
|
218
|
-
on_stdout=on_stdout,
|
|
219
|
-
on_stderr=on_stderr,
|
|
220
|
-
)
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
def _start(
|
|
224
|
-
self,
|
|
225
|
-
cmd: str,
|
|
226
|
-
envs: Optional[Dict[str, str]] = None,
|
|
227
|
-
user: Username = "user",
|
|
228
|
-
cwd: Optional[str] = None,
|
|
229
|
-
timeout: Optional[float] = 60,
|
|
230
|
-
request_timeout: Optional[float] = None,
|
|
231
|
-
):
|
|
232
|
-
events = self._rpc.start(
|
|
233
|
-
api_pb2.StartRequest(
|
|
234
|
-
process=api_pb2.ProcessConfig(
|
|
235
|
-
cmd="/bin/bash",
|
|
236
|
-
envs=envs,
|
|
237
|
-
args=["-l","-c", cmd],
|
|
238
|
-
cwd=cwd,
|
|
239
|
-
),
|
|
240
|
-
),
|
|
241
|
-
self._headers,
|
|
242
|
-
timeout_seconds=self._connection_config.get_request_timeout(
|
|
243
|
-
request_timeout
|
|
244
|
-
),
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
try:
|
|
248
|
-
start_event = events.__next__()
|
|
249
|
-
|
|
250
|
-
if not start_event.HasField("event"):
|
|
251
|
-
raise SandboxException(
|
|
252
|
-
f"Failed to start process: expected start event, got {start_event}"
|
|
253
|
-
)
|
|
254
|
-
|
|
255
|
-
return CommandHandle(
|
|
256
|
-
pid=start_event.event.start.pid,
|
|
257
|
-
handle_kill=lambda: self.kill(start_event.event.start.pid),
|
|
258
|
-
events=events,
|
|
259
|
-
)
|
|
260
|
-
except Exception as e:
|
|
261
|
-
raise handle_rpc_exception(e)
|
|
262
|
-
|
|
263
|
-
def connect(
|
|
264
|
-
self,
|
|
265
|
-
pid: int,
|
|
266
|
-
timeout: Optional[float] = 60,
|
|
267
|
-
request_timeout: Optional[float] = None,
|
|
268
|
-
):
|
|
269
|
-
"""
|
|
270
|
-
Connects to a running command.
|
|
271
|
-
You can use `CommandHandle.wait()` to wait for the command to finish and get execution results.
|
|
272
|
-
|
|
273
|
-
:param pid: Process ID of the command to connect to. You can get the list of processes using `sandbox.commands.list()`
|
|
274
|
-
:param timeout: Timeout for the connection in **seconds**. Using `0` will not limit the connection time
|
|
275
|
-
:param request_timeout: Timeout for the request in **seconds**
|
|
276
|
-
|
|
277
|
-
:return: `CommandHandle` handle to interact with the running command
|
|
278
|
-
"""
|
|
279
|
-
events = self._rpc.connect(
|
|
280
|
-
api_pb2.ConnectRequest(
|
|
281
|
-
process=api_pb2.ProcessSelector(pid=pid),
|
|
282
|
-
),
|
|
283
|
-
self._headers,
|
|
284
|
-
timeout_seconds=self._connection_config.get_request_timeout(
|
|
285
|
-
request_timeout
|
|
286
|
-
),
|
|
287
|
-
)
|
|
288
|
-
try:
|
|
289
|
-
start_event = events.__next__()
|
|
290
|
-
if not start_event.HasField("event"):
|
|
291
|
-
raise SandboxException(
|
|
292
|
-
f"Failed to connect to process: expected start event, got {start_event}"
|
|
293
|
-
)
|
|
294
|
-
return CommandHandle(
|
|
295
|
-
pid=start_event.event.start.pid,
|
|
296
|
-
handle_kill=lambda: self.kill(start_event.event.start.pid),
|
|
297
|
-
events=events,
|
|
298
|
-
)
|
|
299
|
-
except Exception as e:
|
|
300
|
-
raise handle_rpc_exception(e)
|
|
1
|
+
from typing import Callable, Dict, List, Literal, Optional, Union, overload
|
|
2
|
+
|
|
3
|
+
import httpcore
|
|
4
|
+
import urllib3
|
|
5
|
+
|
|
6
|
+
from ... import csx_connect
|
|
7
|
+
from ...connection_config import (
|
|
8
|
+
KEEPALIVE_PING_HEADER,
|
|
9
|
+
KEEPALIVE_PING_INTERVAL_SEC,
|
|
10
|
+
ConnectionConfig,
|
|
11
|
+
Username,
|
|
12
|
+
)
|
|
13
|
+
from ...exceptions import SandboxException
|
|
14
|
+
from ...generated import api_pb2, api_pb2_connect
|
|
15
|
+
from ...generated.rpc import authentication_header, handle_rpc_exception
|
|
16
|
+
from ...sandbox.commands.command_handle import CommandResult
|
|
17
|
+
from ...sandbox.commands.main import ProcessInfo
|
|
18
|
+
from ...sandbox_sync.commands.command_handle import CommandHandle
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Commands:
|
|
22
|
+
"""
|
|
23
|
+
Module for executing commands in the sandbox.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
envd_api_url: str,
|
|
29
|
+
connection_config: ConnectionConfig,
|
|
30
|
+
pool: urllib3.PoolManager,
|
|
31
|
+
) -> None:
|
|
32
|
+
self._connection_config = connection_config
|
|
33
|
+
self._rpc = api_pb2_connect.ProcessClient(
|
|
34
|
+
envd_api_url,
|
|
35
|
+
http_client=pool,
|
|
36
|
+
)
|
|
37
|
+
self._headers = connection_config.headers
|
|
38
|
+
self._pool = pool
|
|
39
|
+
|
|
40
|
+
def list(
|
|
41
|
+
self,
|
|
42
|
+
request_timeout: Optional[float] = None,
|
|
43
|
+
) -> List[ProcessInfo]:
|
|
44
|
+
"""
|
|
45
|
+
Lists all running commands and PTY sessions.
|
|
46
|
+
|
|
47
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
48
|
+
|
|
49
|
+
:return: List of running commands and PTY sessions
|
|
50
|
+
"""
|
|
51
|
+
try:
|
|
52
|
+
res = self._rpc.list(
|
|
53
|
+
api_pb2.ListRequest(),
|
|
54
|
+
self._headers,
|
|
55
|
+
timeout_seconds=self._connection_config.get_request_timeout(
|
|
56
|
+
request_timeout
|
|
57
|
+
),
|
|
58
|
+
)
|
|
59
|
+
return [
|
|
60
|
+
ProcessInfo(
|
|
61
|
+
pid=p.pid,
|
|
62
|
+
tag=p.tag,
|
|
63
|
+
cmd=p.config.cmd,
|
|
64
|
+
args=list(p.config.args),
|
|
65
|
+
envs=dict(p.config.envs),
|
|
66
|
+
cwd=p.config.cwd,
|
|
67
|
+
)
|
|
68
|
+
for p in res.processes
|
|
69
|
+
]
|
|
70
|
+
except Exception as e:
|
|
71
|
+
raise handle_rpc_exception(e)
|
|
72
|
+
|
|
73
|
+
def kill(
|
|
74
|
+
self,
|
|
75
|
+
pid: int,
|
|
76
|
+
request_timeout: Optional[float] = None,
|
|
77
|
+
) -> bool:
|
|
78
|
+
"""
|
|
79
|
+
Kills a running command specified by its process ID.
|
|
80
|
+
It uses `SIGKILL` signal to kill the command.
|
|
81
|
+
|
|
82
|
+
:param pid: Process ID of the command. You can get the list of processes using `sandbox.commands.list()`
|
|
83
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
84
|
+
|
|
85
|
+
:return: `True` if the command was killed, `False` if the command was not found
|
|
86
|
+
"""
|
|
87
|
+
try:
|
|
88
|
+
self._rpc.send_signal(
|
|
89
|
+
api_pb2.SendSignalRequest(
|
|
90
|
+
process=api_pb2.ProcessSelector(pid=pid),
|
|
91
|
+
signal=api_pb2.Signal.SIGNAL_SIGKILL,
|
|
92
|
+
),
|
|
93
|
+
self._headers,
|
|
94
|
+
timeout_seconds=self._connection_config.get_request_timeout(
|
|
95
|
+
request_timeout
|
|
96
|
+
),
|
|
97
|
+
)
|
|
98
|
+
return True
|
|
99
|
+
except Exception as e:
|
|
100
|
+
if "not found" in str(e):
|
|
101
|
+
return False
|
|
102
|
+
raise handle_rpc_exception(e)
|
|
103
|
+
|
|
104
|
+
def send_stdin(
|
|
105
|
+
self,
|
|
106
|
+
pid: int,
|
|
107
|
+
data: str,
|
|
108
|
+
request_timeout: Optional[float] = None,
|
|
109
|
+
):
|
|
110
|
+
"""
|
|
111
|
+
Send data to command stdin.
|
|
112
|
+
|
|
113
|
+
:param pid Process ID of the command. You can get the list of processes using `sandbox.commands.list()`.
|
|
114
|
+
:param data: Data to send to the command
|
|
115
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
116
|
+
"""
|
|
117
|
+
try:
|
|
118
|
+
self._rpc.send_input(
|
|
119
|
+
api_pb2.SendInputRequest(
|
|
120
|
+
process=api_pb2.ProcessSelector(pid=pid),
|
|
121
|
+
input=api_pb2.ProcessInput(
|
|
122
|
+
stdin=data.encode(),
|
|
123
|
+
),
|
|
124
|
+
),
|
|
125
|
+
self._headers,
|
|
126
|
+
timeout_seconds=self._connection_config.get_request_timeout(
|
|
127
|
+
request_timeout
|
|
128
|
+
),
|
|
129
|
+
)
|
|
130
|
+
except Exception as e:
|
|
131
|
+
raise handle_rpc_exception(e)
|
|
132
|
+
|
|
133
|
+
@overload
|
|
134
|
+
def run(
|
|
135
|
+
self,
|
|
136
|
+
cmd: str,
|
|
137
|
+
background: Union[Literal[False], None] = None,
|
|
138
|
+
envs: Optional[Dict[str, str]] = None,
|
|
139
|
+
user: Username = "user",
|
|
140
|
+
cwd: Optional[str] = None,
|
|
141
|
+
on_stdout: Optional[Callable[[str], None]] = None,
|
|
142
|
+
on_stderr: Optional[Callable[[str], None]] = None,
|
|
143
|
+
timeout: Optional[float] = 60,
|
|
144
|
+
request_timeout: Optional[float] = None,
|
|
145
|
+
) -> CommandResult:
|
|
146
|
+
"""
|
|
147
|
+
Start a new command and wait until it finishes executing.
|
|
148
|
+
|
|
149
|
+
:param cmd: Command to execute
|
|
150
|
+
:param background: **`False` if the command should be executed in the foreground**, `True` if the command should be executed in the background
|
|
151
|
+
:param envs: Environment variables used for the command
|
|
152
|
+
:param user: User to run the command as
|
|
153
|
+
:param cwd: Working directory to run the command
|
|
154
|
+
:param on_stdout: Callback for command stdout output
|
|
155
|
+
:param on_stderr: Callback for command stderr output
|
|
156
|
+
:param timeout: Timeout for the command connection in **seconds**. Using `0` will not limit the command connection time
|
|
157
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
158
|
+
|
|
159
|
+
:return: `CommandResult` result of the command execution
|
|
160
|
+
"""
|
|
161
|
+
...
|
|
162
|
+
|
|
163
|
+
@overload
|
|
164
|
+
def run(
|
|
165
|
+
self,
|
|
166
|
+
cmd: str,
|
|
167
|
+
background: Literal[True],
|
|
168
|
+
envs: Optional[Dict[str, str]] = None,
|
|
169
|
+
user: Username = "user",
|
|
170
|
+
cwd: Optional[str] = None,
|
|
171
|
+
on_stdout: None = None,
|
|
172
|
+
on_stderr: None = None,
|
|
173
|
+
timeout: Optional[float] = 60,
|
|
174
|
+
request_timeout: Optional[float] = None,
|
|
175
|
+
) -> CommandHandle:
|
|
176
|
+
"""
|
|
177
|
+
Start a new command and return a handle to interact with it.
|
|
178
|
+
|
|
179
|
+
:param cmd: Command to execute
|
|
180
|
+
:param background: `False` if the command should be executed in the foreground, **`True` if the command should be executed in the background**
|
|
181
|
+
:param envs: Environment variables used for the command
|
|
182
|
+
:param user: User to run the command as
|
|
183
|
+
:param cwd: Working directory to run the command
|
|
184
|
+
:param timeout: Timeout for the command connection in **seconds**. Using `0` will not limit the command connection time
|
|
185
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
186
|
+
|
|
187
|
+
:return: `CommandHandle` handle to interact with the running command
|
|
188
|
+
"""
|
|
189
|
+
...
|
|
190
|
+
|
|
191
|
+
def run(
|
|
192
|
+
self,
|
|
193
|
+
cmd: str,
|
|
194
|
+
background: Union[bool, None] = None,
|
|
195
|
+
envs: Optional[Dict[str, str]] = None,
|
|
196
|
+
user: Username = "user",
|
|
197
|
+
cwd: Optional[str] = None,
|
|
198
|
+
on_stdout: Optional[Callable[[str], None]] = None,
|
|
199
|
+
on_stderr: Optional[Callable[[str], None]] = None,
|
|
200
|
+
timeout: Optional[float] = 60,
|
|
201
|
+
request_timeout: Optional[float] = None,
|
|
202
|
+
):
|
|
203
|
+
if background:
|
|
204
|
+
cmd += " &"
|
|
205
|
+
proc = self._start(
|
|
206
|
+
cmd,
|
|
207
|
+
envs,
|
|
208
|
+
user,
|
|
209
|
+
cwd,
|
|
210
|
+
timeout,
|
|
211
|
+
request_timeout,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
return (
|
|
215
|
+
proc
|
|
216
|
+
if background
|
|
217
|
+
else proc.wait(
|
|
218
|
+
on_stdout=on_stdout,
|
|
219
|
+
on_stderr=on_stderr,
|
|
220
|
+
)
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
def _start(
|
|
224
|
+
self,
|
|
225
|
+
cmd: str,
|
|
226
|
+
envs: Optional[Dict[str, str]] = None,
|
|
227
|
+
user: Username = "user",
|
|
228
|
+
cwd: Optional[str] = None,
|
|
229
|
+
timeout: Optional[float] = 60,
|
|
230
|
+
request_timeout: Optional[float] = None,
|
|
231
|
+
):
|
|
232
|
+
events = self._rpc.start(
|
|
233
|
+
api_pb2.StartRequest(
|
|
234
|
+
process=api_pb2.ProcessConfig(
|
|
235
|
+
cmd="/bin/bash",
|
|
236
|
+
envs=envs,
|
|
237
|
+
args=["-l","-c", cmd],
|
|
238
|
+
cwd=cwd,
|
|
239
|
+
),
|
|
240
|
+
),
|
|
241
|
+
self._headers,
|
|
242
|
+
timeout_seconds=self._connection_config.get_request_timeout(
|
|
243
|
+
request_timeout
|
|
244
|
+
),
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
try:
|
|
248
|
+
start_event = events.__next__()
|
|
249
|
+
|
|
250
|
+
if not start_event.HasField("event"):
|
|
251
|
+
raise SandboxException(
|
|
252
|
+
f"Failed to start process: expected start event, got {start_event}"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
return CommandHandle(
|
|
256
|
+
pid=start_event.event.start.pid,
|
|
257
|
+
handle_kill=lambda: self.kill(start_event.event.start.pid),
|
|
258
|
+
events=events,
|
|
259
|
+
)
|
|
260
|
+
except Exception as e:
|
|
261
|
+
raise handle_rpc_exception(e)
|
|
262
|
+
|
|
263
|
+
def connect(
|
|
264
|
+
self,
|
|
265
|
+
pid: int,
|
|
266
|
+
timeout: Optional[float] = 60,
|
|
267
|
+
request_timeout: Optional[float] = None,
|
|
268
|
+
):
|
|
269
|
+
"""
|
|
270
|
+
Connects to a running command.
|
|
271
|
+
You can use `CommandHandle.wait()` to wait for the command to finish and get execution results.
|
|
272
|
+
|
|
273
|
+
:param pid: Process ID of the command to connect to. You can get the list of processes using `sandbox.commands.list()`
|
|
274
|
+
:param timeout: Timeout for the connection in **seconds**. Using `0` will not limit the connection time
|
|
275
|
+
:param request_timeout: Timeout for the request in **seconds**
|
|
276
|
+
|
|
277
|
+
:return: `CommandHandle` handle to interact with the running command
|
|
278
|
+
"""
|
|
279
|
+
events = self._rpc.connect(
|
|
280
|
+
api_pb2.ConnectRequest(
|
|
281
|
+
process=api_pb2.ProcessSelector(pid=pid),
|
|
282
|
+
),
|
|
283
|
+
self._headers,
|
|
284
|
+
timeout_seconds=self._connection_config.get_request_timeout(
|
|
285
|
+
request_timeout
|
|
286
|
+
),
|
|
287
|
+
)
|
|
288
|
+
try:
|
|
289
|
+
start_event = events.__next__()
|
|
290
|
+
if not start_event.HasField("event"):
|
|
291
|
+
raise SandboxException(
|
|
292
|
+
f"Failed to connect to process: expected start event, got {start_event}"
|
|
293
|
+
)
|
|
294
|
+
return CommandHandle(
|
|
295
|
+
pid=start_event.event.start.pid,
|
|
296
|
+
handle_kill=lambda: self.kill(start_event.event.start.pid),
|
|
297
|
+
events=events,
|
|
298
|
+
)
|
|
299
|
+
except Exception as e:
|
|
300
|
+
raise handle_rpc_exception(e)
|