moru 0.1.0__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.
- moru/__init__.py +174 -0
- moru/api/__init__.py +164 -0
- moru/api/client/__init__.py +8 -0
- moru/api/client/api/__init__.py +1 -0
- moru/api/client/api/sandboxes/__init__.py +1 -0
- moru/api/client/api/sandboxes/delete_sandboxes_sandbox_id.py +161 -0
- moru/api/client/api/sandboxes/get_sandboxes.py +176 -0
- moru/api/client/api/sandboxes/get_sandboxes_metrics.py +173 -0
- moru/api/client/api/sandboxes/get_sandboxes_sandbox_id.py +163 -0
- moru/api/client/api/sandboxes/get_sandboxes_sandbox_id_logs.py +199 -0
- moru/api/client/api/sandboxes/get_sandboxes_sandbox_id_metrics.py +212 -0
- moru/api/client/api/sandboxes/get_v2_sandboxes.py +230 -0
- moru/api/client/api/sandboxes/post_sandboxes.py +172 -0
- moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_connect.py +193 -0
- moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_pause.py +165 -0
- moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_refreshes.py +181 -0
- moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_resume.py +189 -0
- moru/api/client/api/sandboxes/post_sandboxes_sandbox_id_timeout.py +193 -0
- moru/api/client/api/templates/__init__.py +1 -0
- moru/api/client/api/templates/delete_templates_template_id.py +157 -0
- moru/api/client/api/templates/get_templates.py +172 -0
- moru/api/client/api/templates/get_templates_template_id.py +195 -0
- moru/api/client/api/templates/get_templates_template_id_builds_build_id_status.py +217 -0
- moru/api/client/api/templates/get_templates_template_id_files_hash.py +180 -0
- moru/api/client/api/templates/patch_templates_template_id.py +183 -0
- moru/api/client/api/templates/post_templates.py +172 -0
- moru/api/client/api/templates/post_templates_template_id.py +181 -0
- moru/api/client/api/templates/post_templates_template_id_builds_build_id.py +170 -0
- moru/api/client/api/templates/post_v2_templates.py +172 -0
- moru/api/client/api/templates/post_v3_templates.py +172 -0
- moru/api/client/api/templates/post_v_2_templates_template_id_builds_build_id.py +192 -0
- moru/api/client/client.py +286 -0
- moru/api/client/errors.py +16 -0
- moru/api/client/models/__init__.py +123 -0
- moru/api/client/models/aws_registry.py +85 -0
- moru/api/client/models/aws_registry_type.py +8 -0
- moru/api/client/models/build_log_entry.py +89 -0
- moru/api/client/models/build_status_reason.py +95 -0
- moru/api/client/models/connect_sandbox.py +59 -0
- moru/api/client/models/created_access_token.py +100 -0
- moru/api/client/models/created_team_api_key.py +166 -0
- moru/api/client/models/disk_metrics.py +91 -0
- moru/api/client/models/error.py +67 -0
- moru/api/client/models/gcp_registry.py +69 -0
- moru/api/client/models/gcp_registry_type.py +8 -0
- moru/api/client/models/general_registry.py +77 -0
- moru/api/client/models/general_registry_type.py +8 -0
- moru/api/client/models/identifier_masking_details.py +83 -0
- moru/api/client/models/listed_sandbox.py +154 -0
- moru/api/client/models/log_level.py +11 -0
- moru/api/client/models/max_team_metric.py +78 -0
- moru/api/client/models/mcp_type_0.py +44 -0
- moru/api/client/models/new_access_token.py +59 -0
- moru/api/client/models/new_sandbox.py +172 -0
- moru/api/client/models/new_team_api_key.py +59 -0
- moru/api/client/models/node.py +155 -0
- moru/api/client/models/node_detail.py +165 -0
- moru/api/client/models/node_metrics.py +122 -0
- moru/api/client/models/node_status.py +11 -0
- moru/api/client/models/node_status_change.py +79 -0
- moru/api/client/models/post_sandboxes_sandbox_id_refreshes_body.py +59 -0
- moru/api/client/models/post_sandboxes_sandbox_id_timeout_body.py +59 -0
- moru/api/client/models/resumed_sandbox.py +68 -0
- moru/api/client/models/sandbox.py +145 -0
- moru/api/client/models/sandbox_detail.py +183 -0
- moru/api/client/models/sandbox_log.py +70 -0
- moru/api/client/models/sandbox_log_entry.py +93 -0
- moru/api/client/models/sandbox_log_entry_fields.py +44 -0
- moru/api/client/models/sandbox_logs.py +91 -0
- moru/api/client/models/sandbox_metric.py +118 -0
- moru/api/client/models/sandbox_network_config.py +92 -0
- moru/api/client/models/sandbox_state.py +9 -0
- moru/api/client/models/sandboxes_with_metrics.py +59 -0
- moru/api/client/models/team.py +83 -0
- moru/api/client/models/team_api_key.py +158 -0
- moru/api/client/models/team_metric.py +86 -0
- moru/api/client/models/team_user.py +68 -0
- moru/api/client/models/template.py +217 -0
- moru/api/client/models/template_build.py +139 -0
- moru/api/client/models/template_build_file_upload.py +70 -0
- moru/api/client/models/template_build_info.py +126 -0
- moru/api/client/models/template_build_request.py +115 -0
- moru/api/client/models/template_build_request_v2.py +88 -0
- moru/api/client/models/template_build_request_v3.py +88 -0
- moru/api/client/models/template_build_start_v2.py +184 -0
- moru/api/client/models/template_build_status.py +11 -0
- moru/api/client/models/template_legacy.py +207 -0
- moru/api/client/models/template_request_response_v3.py +83 -0
- moru/api/client/models/template_step.py +91 -0
- moru/api/client/models/template_update_request.py +59 -0
- moru/api/client/models/template_with_builds.py +148 -0
- moru/api/client/models/update_team_api_key.py +59 -0
- moru/api/client/py.typed +1 -0
- moru/api/client/types.py +54 -0
- moru/api/client_async/__init__.py +50 -0
- moru/api/client_sync/__init__.py +52 -0
- moru/api/metadata.py +14 -0
- moru/connection_config.py +217 -0
- moru/envd/api.py +59 -0
- moru/envd/filesystem/filesystem_connect.py +193 -0
- moru/envd/filesystem/filesystem_pb2.py +76 -0
- moru/envd/filesystem/filesystem_pb2.pyi +233 -0
- moru/envd/process/process_connect.py +155 -0
- moru/envd/process/process_pb2.py +92 -0
- moru/envd/process/process_pb2.pyi +304 -0
- moru/envd/rpc.py +61 -0
- moru/envd/versions.py +6 -0
- moru/exceptions.py +95 -0
- moru/sandbox/commands/command_handle.py +69 -0
- moru/sandbox/commands/main.py +39 -0
- moru/sandbox/filesystem/filesystem.py +94 -0
- moru/sandbox/filesystem/watch_handle.py +60 -0
- moru/sandbox/main.py +210 -0
- moru/sandbox/mcp.py +1120 -0
- moru/sandbox/network.py +8 -0
- moru/sandbox/sandbox_api.py +210 -0
- moru/sandbox/signature.py +45 -0
- moru/sandbox/utils.py +34 -0
- moru/sandbox_async/commands/command.py +336 -0
- moru/sandbox_async/commands/command_handle.py +196 -0
- moru/sandbox_async/commands/pty.py +240 -0
- moru/sandbox_async/filesystem/filesystem.py +531 -0
- moru/sandbox_async/filesystem/watch_handle.py +62 -0
- moru/sandbox_async/main.py +734 -0
- moru/sandbox_async/paginator.py +69 -0
- moru/sandbox_async/sandbox_api.py +325 -0
- moru/sandbox_async/utils.py +7 -0
- moru/sandbox_sync/commands/command.py +328 -0
- moru/sandbox_sync/commands/command_handle.py +150 -0
- moru/sandbox_sync/commands/pty.py +230 -0
- moru/sandbox_sync/filesystem/filesystem.py +518 -0
- moru/sandbox_sync/filesystem/watch_handle.py +69 -0
- moru/sandbox_sync/main.py +726 -0
- moru/sandbox_sync/paginator.py +69 -0
- moru/sandbox_sync/sandbox_api.py +308 -0
- moru/template/consts.py +30 -0
- moru/template/dockerfile_parser.py +275 -0
- moru/template/logger.py +232 -0
- moru/template/main.py +1360 -0
- moru/template/readycmd.py +138 -0
- moru/template/types.py +105 -0
- moru/template/utils.py +320 -0
- moru/template_async/build_api.py +202 -0
- moru/template_async/main.py +366 -0
- moru/template_sync/build_api.py +199 -0
- moru/template_sync/main.py +371 -0
- moru-0.1.0.dist-info/METADATA +63 -0
- moru-0.1.0.dist-info/RECORD +152 -0
- moru-0.1.0.dist-info/WHEEL +4 -0
- moru-0.1.0.dist-info/licenses/LICENSE +9 -0
- moru_connect/__init__.py +1 -0
- moru_connect/client.py +493 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
from moru.envd.filesystem.filesystem_pb2 import EventType
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FilesystemEventType(Enum):
|
|
8
|
+
"""
|
|
9
|
+
Enum representing the type of filesystem event.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
CHMOD = "chmod"
|
|
13
|
+
"""
|
|
14
|
+
Filesystem object permissions were changed.
|
|
15
|
+
"""
|
|
16
|
+
CREATE = "create"
|
|
17
|
+
"""
|
|
18
|
+
Filesystem object was created.
|
|
19
|
+
"""
|
|
20
|
+
REMOVE = "remove"
|
|
21
|
+
"""
|
|
22
|
+
Filesystem object was removed.
|
|
23
|
+
"""
|
|
24
|
+
RENAME = "rename"
|
|
25
|
+
"""
|
|
26
|
+
Filesystem object was renamed.
|
|
27
|
+
"""
|
|
28
|
+
WRITE = "write"
|
|
29
|
+
"""
|
|
30
|
+
Filesystem object was written to.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def map_event_type(event: EventType):
|
|
35
|
+
if event == EventType.EVENT_TYPE_CHMOD:
|
|
36
|
+
return FilesystemEventType.CHMOD
|
|
37
|
+
elif event == EventType.EVENT_TYPE_CREATE:
|
|
38
|
+
return FilesystemEventType.CREATE
|
|
39
|
+
elif event == EventType.EVENT_TYPE_REMOVE:
|
|
40
|
+
return FilesystemEventType.REMOVE
|
|
41
|
+
elif event == EventType.EVENT_TYPE_RENAME:
|
|
42
|
+
return FilesystemEventType.RENAME
|
|
43
|
+
elif event == EventType.EVENT_TYPE_WRITE:
|
|
44
|
+
return FilesystemEventType.WRITE
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass
|
|
48
|
+
class FilesystemEvent:
|
|
49
|
+
"""
|
|
50
|
+
Contains information about the filesystem event - the name of the file and the type of the event.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
name: str
|
|
54
|
+
"""
|
|
55
|
+
Relative path to the filesystem object.
|
|
56
|
+
"""
|
|
57
|
+
type: FilesystemEventType
|
|
58
|
+
"""
|
|
59
|
+
Filesystem operation event type.
|
|
60
|
+
"""
|
moru/sandbox/main.py
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import urllib.parse
|
|
2
|
+
from typing import Optional, TypedDict
|
|
3
|
+
|
|
4
|
+
from packaging.version import Version
|
|
5
|
+
|
|
6
|
+
from moru.connection_config import ConnectionConfig, default_username
|
|
7
|
+
from moru.envd.api import ENVD_API_FILES_ROUTE
|
|
8
|
+
from moru.envd.versions import ENVD_DEFAULT_USER
|
|
9
|
+
from moru.sandbox.signature import get_signature
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SandboxOpts(TypedDict):
|
|
13
|
+
sandbox_id: str
|
|
14
|
+
sandbox_domain: Optional[str]
|
|
15
|
+
envd_version: Version
|
|
16
|
+
envd_access_token: Optional[str]
|
|
17
|
+
sandbox_url: Optional[str]
|
|
18
|
+
traffic_access_token: Optional[str]
|
|
19
|
+
connection_config: ConnectionConfig
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SandboxBase:
|
|
23
|
+
mcp_port = 50005
|
|
24
|
+
|
|
25
|
+
default_sandbox_timeout = 300
|
|
26
|
+
|
|
27
|
+
default_template = "base"
|
|
28
|
+
default_mcp_template = "mcp-gateway"
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
sandbox_id: str,
|
|
33
|
+
envd_version: Version,
|
|
34
|
+
envd_access_token: Optional[str],
|
|
35
|
+
sandbox_domain: Optional[str],
|
|
36
|
+
connection_config: ConnectionConfig,
|
|
37
|
+
traffic_access_token: Optional[str] = None,
|
|
38
|
+
):
|
|
39
|
+
self.__connection_config = connection_config
|
|
40
|
+
self.__sandbox_id = sandbox_id
|
|
41
|
+
self.__sandbox_domain = sandbox_domain or self.connection_config.domain
|
|
42
|
+
self.__envd_version = envd_version
|
|
43
|
+
self.__envd_access_token = envd_access_token
|
|
44
|
+
self.__traffic_access_token = traffic_access_token
|
|
45
|
+
self.__envd_api_url = self.connection_config.get_sandbox_url(
|
|
46
|
+
self.sandbox_id, self.sandbox_domain
|
|
47
|
+
)
|
|
48
|
+
self.__mcp_token: Optional[str] = None
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def _envd_access_token(self) -> Optional[str]:
|
|
52
|
+
"""Private property to access the envd token"""
|
|
53
|
+
return self.__envd_access_token
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def _mcp_token(self) -> Optional[str]:
|
|
57
|
+
return self.__mcp_token
|
|
58
|
+
|
|
59
|
+
@_mcp_token.setter
|
|
60
|
+
def _mcp_token(self, token: str) -> None:
|
|
61
|
+
self.__mcp_token = token
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def connection_config(self) -> ConnectionConfig:
|
|
65
|
+
return self.__connection_config
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def _envd_version(self) -> Version:
|
|
69
|
+
return self.__envd_version
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def traffic_access_token(self) -> Optional[str]:
|
|
73
|
+
return self.__traffic_access_token
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def sandbox_domain(self) -> Optional[str]:
|
|
77
|
+
return self.__sandbox_domain
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def envd_api_url(self) -> str:
|
|
81
|
+
return self.__envd_api_url
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def sandbox_id(self) -> str:
|
|
85
|
+
"""
|
|
86
|
+
Unique identifier of the sandbox.
|
|
87
|
+
"""
|
|
88
|
+
return self.__sandbox_id
|
|
89
|
+
|
|
90
|
+
def _file_url(
|
|
91
|
+
self,
|
|
92
|
+
path: str,
|
|
93
|
+
user: Optional[str] = None,
|
|
94
|
+
signature: Optional[str] = None,
|
|
95
|
+
signature_expiration: Optional[int] = None,
|
|
96
|
+
) -> str:
|
|
97
|
+
url = urllib.parse.urljoin(self.envd_api_url, ENVD_API_FILES_ROUTE)
|
|
98
|
+
query = {"path": path} if path else {}
|
|
99
|
+
|
|
100
|
+
if user:
|
|
101
|
+
query["username"] = user
|
|
102
|
+
|
|
103
|
+
if signature:
|
|
104
|
+
query["signature"] = signature
|
|
105
|
+
|
|
106
|
+
if signature_expiration:
|
|
107
|
+
if signature is None:
|
|
108
|
+
raise ValueError("signature_expiration requires signature to be set")
|
|
109
|
+
query["signature_expiration"] = str(signature_expiration)
|
|
110
|
+
|
|
111
|
+
params = urllib.parse.urlencode(
|
|
112
|
+
query,
|
|
113
|
+
quote_via=urllib.parse.quote,
|
|
114
|
+
)
|
|
115
|
+
url = urllib.parse.urljoin(url, f"?{params}")
|
|
116
|
+
|
|
117
|
+
return url
|
|
118
|
+
|
|
119
|
+
def download_url(
|
|
120
|
+
self,
|
|
121
|
+
path: str,
|
|
122
|
+
user: Optional[str] = None,
|
|
123
|
+
use_signature_expiration: Optional[int] = None,
|
|
124
|
+
) -> str:
|
|
125
|
+
"""
|
|
126
|
+
Get the URL to download a file from the sandbox.
|
|
127
|
+
|
|
128
|
+
:param path: Path to the file to download
|
|
129
|
+
:param user: User to download the file as
|
|
130
|
+
:param use_signature_expiration: Expiration time for the signed URL in seconds
|
|
131
|
+
|
|
132
|
+
:return: URL for downloading file
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
username = user
|
|
136
|
+
if username is None and self._envd_version < ENVD_DEFAULT_USER:
|
|
137
|
+
username = default_username
|
|
138
|
+
|
|
139
|
+
use_signature = self._envd_access_token is not None
|
|
140
|
+
if use_signature:
|
|
141
|
+
signature = get_signature(
|
|
142
|
+
path,
|
|
143
|
+
"read",
|
|
144
|
+
username,
|
|
145
|
+
self._envd_access_token,
|
|
146
|
+
use_signature_expiration,
|
|
147
|
+
)
|
|
148
|
+
return self._file_url(
|
|
149
|
+
path, username, signature["signature"], signature["expiration"]
|
|
150
|
+
)
|
|
151
|
+
else:
|
|
152
|
+
return self._file_url(path, username)
|
|
153
|
+
|
|
154
|
+
def upload_url(
|
|
155
|
+
self,
|
|
156
|
+
path: str,
|
|
157
|
+
user: Optional[str] = None,
|
|
158
|
+
use_signature_expiration: Optional[int] = None,
|
|
159
|
+
) -> str:
|
|
160
|
+
"""
|
|
161
|
+
Get the URL to upload a file to the sandbox.
|
|
162
|
+
|
|
163
|
+
You have to send a POST request to this URL with the file as multipart/form-data.
|
|
164
|
+
|
|
165
|
+
:param path: Path to the file to upload
|
|
166
|
+
:param user: User to upload the file as
|
|
167
|
+
:param use_signature_expiration: Expiration time for the signed URL in seconds
|
|
168
|
+
|
|
169
|
+
:return: URL for uploading file
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
username = user
|
|
173
|
+
if username is None and self._envd_version < ENVD_DEFAULT_USER:
|
|
174
|
+
username = default_username
|
|
175
|
+
|
|
176
|
+
use_signature = self._envd_access_token is not None
|
|
177
|
+
if use_signature:
|
|
178
|
+
signature = get_signature(
|
|
179
|
+
path,
|
|
180
|
+
"write",
|
|
181
|
+
username,
|
|
182
|
+
self._envd_access_token,
|
|
183
|
+
use_signature_expiration,
|
|
184
|
+
)
|
|
185
|
+
return self._file_url(
|
|
186
|
+
path, username, signature["signature"], signature["expiration"]
|
|
187
|
+
)
|
|
188
|
+
else:
|
|
189
|
+
return self._file_url(path, username)
|
|
190
|
+
|
|
191
|
+
def get_host(self, port: int) -> str:
|
|
192
|
+
"""
|
|
193
|
+
Get the host address to connect to the sandbox.
|
|
194
|
+
You can then use this address to connect to the sandbox port from outside the sandbox via HTTP or WebSocket.
|
|
195
|
+
|
|
196
|
+
:param port: Port to connect to
|
|
197
|
+
|
|
198
|
+
:return: Host address to connect to
|
|
199
|
+
"""
|
|
200
|
+
return self.connection_config.get_host(
|
|
201
|
+
self.sandbox_id, self.sandbox_domain, port
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
def get_mcp_url(self) -> str:
|
|
205
|
+
"""
|
|
206
|
+
Get the MCP URL for the sandbox.
|
|
207
|
+
|
|
208
|
+
:returns MCP URL for the sandbox.
|
|
209
|
+
"""
|
|
210
|
+
return f"https://{self.get_host(self.mcp_port)}/mcp"
|