matlab-proxy 0.25.0__py3-none-any.whl → 0.26.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.
Potentially problematic release.
This version of matlab-proxy might be problematic. Click here for more details.
- matlab_proxy/app.py +66 -12
- matlab_proxy/constants.py +1 -0
- matlab_proxy/gui/index.html +1 -1
- matlab_proxy/gui/static/js/{index.qK3VCGVb.js → index.CZgGkMCD.js} +15 -15
- matlab_proxy/settings.py +22 -1
- matlab_proxy/util/cookie_jar.py +72 -0
- matlab_proxy/util/mwi/environment_variables.py +10 -0
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/METADATA +4 -1
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/RECORD +24 -21
- matlab_proxy_manager/lib/api.py +156 -114
- matlab_proxy_manager/storage/server.py +5 -2
- matlab_proxy_manager/utils/constants.py +2 -1
- matlab_proxy_manager/utils/environment_variables.py +6 -1
- matlab_proxy_manager/utils/exceptions.py +45 -0
- matlab_proxy_manager/utils/helpers.py +2 -2
- matlab_proxy_manager/utils/logger.py +4 -1
- matlab_proxy_manager/web/app.py +71 -19
- tests/unit/test_app.py +116 -17
- tests/unit/test_settings.py +26 -6
- tests/unit/util/test_cookie_jar.py +252 -0
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/LICENSE.md +0 -0
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/WHEEL +0 -0
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/entry_points.txt +0 -0
- {matlab_proxy-0.25.0.dist-info → matlab_proxy-0.26.0.dist-info}/top_level.txt +0 -0
matlab_proxy_manager/lib/api.py
CHANGED
|
@@ -3,13 +3,14 @@ import asyncio
|
|
|
3
3
|
import os
|
|
4
4
|
import secrets
|
|
5
5
|
import subprocess
|
|
6
|
-
from typing import List,
|
|
6
|
+
from typing import List, Tuple
|
|
7
7
|
|
|
8
8
|
import matlab_proxy
|
|
9
|
+
import matlab_proxy.util.mwi.environment_variables as mwi_env
|
|
9
10
|
import matlab_proxy.util.system as mwi_sys
|
|
10
11
|
from matlab_proxy_manager.storage.file_repository import FileRepository
|
|
11
12
|
from matlab_proxy_manager.storage.server import ServerProcess
|
|
12
|
-
from matlab_proxy_manager.utils import constants, helpers, logger
|
|
13
|
+
from matlab_proxy_manager.utils import constants, exceptions, helpers, logger
|
|
13
14
|
|
|
14
15
|
# Used to list all the public-facing APIs exported by this module.
|
|
15
16
|
__all__ = ["shutdown", "start_matlab_proxy_for_kernel", "start_matlab_proxy_for_jsp"]
|
|
@@ -20,7 +21,7 @@ log = logger.get(init=True)
|
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
async def start_matlab_proxy_for_kernel(
|
|
23
|
-
caller_id: str, parent_id: str, is_shared_matlab: bool
|
|
24
|
+
caller_id: str, parent_id: str, is_shared_matlab: bool, base_url_prefix: str = ""
|
|
24
25
|
):
|
|
25
26
|
"""
|
|
26
27
|
Starts a MATLAB proxy server specifically for MATLAB Kernel.
|
|
@@ -29,12 +30,18 @@ async def start_matlab_proxy_for_kernel(
|
|
|
29
30
|
set to None, for starting the MATLAB proxy server via proxy manager.
|
|
30
31
|
"""
|
|
31
32
|
return await _start_matlab_proxy(
|
|
32
|
-
caller_id=caller_id,
|
|
33
|
+
caller_id=caller_id,
|
|
34
|
+
ctx=parent_id,
|
|
35
|
+
is_shared_matlab=is_shared_matlab,
|
|
36
|
+
base_url_prefix=base_url_prefix,
|
|
33
37
|
)
|
|
34
38
|
|
|
35
39
|
|
|
36
40
|
async def start_matlab_proxy_for_jsp(
|
|
37
|
-
parent_id: str,
|
|
41
|
+
parent_id: str,
|
|
42
|
+
is_shared_matlab: bool,
|
|
43
|
+
mpm_auth_token: str,
|
|
44
|
+
base_url_prefix: str = "",
|
|
38
45
|
):
|
|
39
46
|
"""
|
|
40
47
|
Starts a MATLAB proxy server specifically for Jupyter Server Proxy (JSP) - Open MATLAB launcher.
|
|
@@ -47,120 +54,136 @@ async def start_matlab_proxy_for_jsp(
|
|
|
47
54
|
ctx=parent_id,
|
|
48
55
|
is_shared_matlab=is_shared_matlab,
|
|
49
56
|
mpm_auth_token=mpm_auth_token,
|
|
57
|
+
base_url_prefix=base_url_prefix,
|
|
50
58
|
)
|
|
51
59
|
|
|
52
60
|
|
|
53
|
-
async def _start_matlab_proxy(**options) ->
|
|
61
|
+
async def _start_matlab_proxy(**options) -> dict:
|
|
54
62
|
"""
|
|
55
|
-
|
|
63
|
+
Starts a MATLAB proxy server with the specified options.
|
|
56
64
|
|
|
57
|
-
This function
|
|
58
|
-
|
|
65
|
+
This function validates the provided options, checks for existing server instances,
|
|
66
|
+
and either returns an existing server process or starts a new MATLAB proxy server.
|
|
67
|
+
It ensures that required arguments are present, handles token generation, and manages
|
|
68
|
+
server readiness and error handling.
|
|
59
69
|
|
|
60
|
-
Args
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
Args:
|
|
71
|
+
**options: Arbitrary keyword arguments containing the following keys:
|
|
72
|
+
- caller_id (str): The identifier for the caller (kernel id for kernels, "jsp" for JSP).
|
|
73
|
+
- ctx (str): The context in which the server is being started (parent pid).
|
|
74
|
+
- is_shared_matlab (bool): Flag indicating if the MATLAB proxy is shared.
|
|
75
|
+
- mpm_auth_token (Optional[str]): Authentication token for the MATLAB proxy manager.
|
|
76
|
+
- base_url_prefix (Optional[str]): Custom URL path which gets added to mwi_base_url
|
|
67
77
|
|
|
68
78
|
Returns:
|
|
69
|
-
|
|
79
|
+
dict: A dictionary representation of the server process, including any errors encountered.
|
|
70
80
|
|
|
71
81
|
Raises:
|
|
72
82
|
ValueError: If `caller_id` is "default" and `is_shared_matlab` is False.
|
|
73
83
|
"""
|
|
74
|
-
|
|
75
|
-
required_args: List[str] = ["caller_id", "ctx", "is_shared_matlab"]
|
|
76
|
-
missing_args: List[str] = [arg for arg in required_args if arg not in options]
|
|
77
|
-
|
|
78
|
-
if missing_args:
|
|
79
|
-
raise ValueError(f"Missing required arguments: {', '.join(missing_args)}")
|
|
84
|
+
_validate_required_arguments(options)
|
|
80
85
|
|
|
81
86
|
caller_id: str = options["caller_id"]
|
|
82
87
|
ctx: str = options["ctx"]
|
|
83
88
|
is_shared_matlab: bool = options.get("is_shared_matlab", True)
|
|
84
|
-
mpm_auth_token
|
|
89
|
+
mpm_auth_token = options.get("mpm_auth_token", None) or secrets.token_hex(32)
|
|
85
90
|
|
|
86
91
|
if not is_shared_matlab and caller_id == "default":
|
|
87
92
|
raise ValueError(
|
|
88
93
|
"Caller id cannot be default when matlab proxy is not shareable"
|
|
89
94
|
)
|
|
90
95
|
|
|
91
|
-
mpm_auth_token = mpm_auth_token or secrets.token_hex(32)
|
|
92
|
-
|
|
93
96
|
# Cleanup stale entries before starting new instance of matlab proxy server
|
|
94
97
|
helpers._are_orphaned_servers_deleted(ctx)
|
|
95
98
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
client_id = caller_id if not is_shared_matlab else "default"
|
|
100
|
+
matlab_session_dir = f"{ctx}_{client_id}"
|
|
101
|
+
filename = f"{ctx}_{caller_id}"
|
|
102
|
+
proxy_manager_root_dir = helpers.create_and_get_proxy_manager_data_dir()
|
|
103
|
+
existing_matlab_proxy_process = ServerProcess.find_existing_server(
|
|
104
|
+
proxy_manager_root_dir, matlab_session_dir
|
|
105
|
+
)
|
|
102
106
|
|
|
103
|
-
if
|
|
107
|
+
if existing_matlab_proxy_process:
|
|
104
108
|
log.debug("Found existing server for aliasing")
|
|
105
109
|
|
|
106
110
|
# Create a backend file for this caller for reference tracking
|
|
107
|
-
helpers.create_state_file(
|
|
111
|
+
helpers.create_state_file(
|
|
112
|
+
proxy_manager_root_dir, existing_matlab_proxy_process, filename
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
return existing_matlab_proxy_process.as_dict()
|
|
108
116
|
|
|
109
117
|
# Create a new matlab proxy server
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
118
|
+
try:
|
|
119
|
+
base_url_prefix = options.get("base_url_prefix", "")
|
|
120
|
+
|
|
121
|
+
# Prepare matlab proxy command and required environment variables
|
|
122
|
+
matlab_proxy_cmd, matlab_proxy_env = _prepare_cmd_and_env_for_matlab_proxy(
|
|
123
|
+
client_id, base_url_prefix
|
|
113
124
|
)
|
|
114
125
|
|
|
126
|
+
log.debug(
|
|
127
|
+
"Starting new matlab proxy server using ctx=%s, client_id=%s, is_shared_matlab=%s",
|
|
128
|
+
ctx,
|
|
129
|
+
client_id,
|
|
130
|
+
is_shared_matlab,
|
|
131
|
+
)
|
|
132
|
+
# Start the matlab proxy process
|
|
133
|
+
process_id, url = await _start_subprocess(matlab_proxy_cmd, matlab_proxy_env)
|
|
134
|
+
log.debug("MATLAB proxy process url: %s", url)
|
|
135
|
+
|
|
136
|
+
matlab_proxy_process = ServerProcess(
|
|
137
|
+
server_url=url,
|
|
138
|
+
mwi_base_url=matlab_proxy_env.get(mwi_env.get_env_name_base_url()),
|
|
139
|
+
headers=helpers.convert_mwi_env_vars_to_header_format(
|
|
140
|
+
matlab_proxy_env, "MWI"
|
|
141
|
+
),
|
|
142
|
+
pid=str(process_id),
|
|
143
|
+
parent_pid=ctx,
|
|
144
|
+
id=matlab_session_dir,
|
|
145
|
+
type="shared" if is_shared_matlab else "isolated",
|
|
146
|
+
mpm_auth_token=mpm_auth_token,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
await _check_for_process_readiness(matlab_proxy_process)
|
|
150
|
+
|
|
115
151
|
# Store the newly created server into filesystem
|
|
116
|
-
|
|
117
|
-
|
|
152
|
+
helpers.create_state_file(
|
|
153
|
+
proxy_manager_root_dir, matlab_proxy_process, filename
|
|
154
|
+
)
|
|
155
|
+
return matlab_proxy_process.as_dict()
|
|
118
156
|
|
|
119
|
-
|
|
157
|
+
# Return a server process instance with the errors information set
|
|
158
|
+
except exceptions.ProcessStartError as pse:
|
|
159
|
+
return ServerProcess(errors=[str(pse)]).as_dict()
|
|
160
|
+
except exceptions.ServerReadinessError as sre:
|
|
161
|
+
return ServerProcess(errors=[str(sre)]).as_dict()
|
|
162
|
+
except Exception as e:
|
|
163
|
+
log.error("Error starting matlab proxy server: %s", str(e))
|
|
164
|
+
return ServerProcess(errors=[str(e)]).as_dict()
|
|
120
165
|
|
|
121
166
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
Starts a MATLAB proxy server.
|
|
167
|
+
def _validate_required_arguments(options):
|
|
168
|
+
# Validates that all required arguments are present in the supplied values
|
|
169
|
+
required_args: List[str] = ["caller_id", "ctx", "is_shared_matlab"]
|
|
170
|
+
missing_args: List[str] = [arg for arg in required_args if arg not in options]
|
|
127
171
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
2. Initializes the MATLAB proxy process.
|
|
131
|
-
3. Checks if the MATLAB proxy server is ready.
|
|
132
|
-
4. Creates and returns a ServerProcess instance if the server is ready.
|
|
172
|
+
if missing_args:
|
|
173
|
+
raise ValueError(f"Missing required arguments: {', '.join(missing_args)}")
|
|
133
174
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
otherwise None.
|
|
175
|
+
|
|
176
|
+
async def _check_for_process_readiness(matlab_proxy_process: ServerProcess):
|
|
137
177
|
"""
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
# Prepare matlab proxy command and required environment variables
|
|
141
|
-
matlab_proxy_cmd, matlab_proxy_env = _prepare_cmd_and_env_for_matlab_proxy()
|
|
142
|
-
|
|
143
|
-
# Start the matlab proxy process
|
|
144
|
-
result = await _start_subprocess(matlab_proxy_cmd, matlab_proxy_env, server_id)
|
|
145
|
-
if not result:
|
|
146
|
-
log.error("Could not start matlab proxy")
|
|
147
|
-
return None
|
|
148
|
-
|
|
149
|
-
process_id, url, mwi_base_url = result
|
|
150
|
-
|
|
151
|
-
log.debug("Matlab proxy process info: %s, %s", url, mwi_base_url)
|
|
152
|
-
matlab_proxy_process = ServerProcess(
|
|
153
|
-
server_url=url,
|
|
154
|
-
mwi_base_url=mwi_base_url,
|
|
155
|
-
headers=helpers.convert_mwi_env_vars_to_header_format(matlab_proxy_env, "MWI"),
|
|
156
|
-
pid=str(process_id),
|
|
157
|
-
parent_pid=ctx,
|
|
158
|
-
id=key,
|
|
159
|
-
type="shared" if is_shared_matlab else "named",
|
|
160
|
-
mpm_auth_token=mpm_auth_token,
|
|
161
|
-
)
|
|
178
|
+
Checks if the MATLAB proxy server is ready.
|
|
162
179
|
|
|
163
|
-
|
|
180
|
+
Args:
|
|
181
|
+
matlab_proxy_process (ServerProcess): Deserialized matlab-proxy process
|
|
182
|
+
|
|
183
|
+
Raises:
|
|
184
|
+
ServerReadinessError: If the MATLAB proxy server is not ready after retries.
|
|
185
|
+
"""
|
|
186
|
+
# Check for the matlab proxy server readiness - with retries
|
|
164
187
|
if not helpers.is_server_ready(
|
|
165
188
|
url=matlab_proxy_process.absolute_url, retries=7, backoff_factor=0.5
|
|
166
189
|
):
|
|
@@ -168,19 +191,21 @@ async def _start_subprocess_and_check_for_readiness(
|
|
|
168
191
|
"MATLAB Proxy Server unavailable: matlab-proxy-app failed to start or has timed out."
|
|
169
192
|
)
|
|
170
193
|
matlab_proxy_process.shutdown()
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return matlab_proxy_process
|
|
194
|
+
raise exceptions.ServerReadinessError()
|
|
174
195
|
|
|
175
196
|
|
|
176
|
-
def _prepare_cmd_and_env_for_matlab_proxy():
|
|
197
|
+
def _prepare_cmd_and_env_for_matlab_proxy(client_id: str, base_url_prefix: str):
|
|
177
198
|
"""
|
|
178
199
|
Prepare the command and environment variables for starting the MATLAB proxy.
|
|
179
200
|
|
|
180
201
|
Returns:
|
|
181
202
|
Tuple: A tuple containing the MATLAB proxy command and environment variables.
|
|
182
203
|
"""
|
|
183
|
-
from jupyter_matlab_proxy
|
|
204
|
+
# Get config from matlab_proxy module if jupyter_matlab_proxy module is not available
|
|
205
|
+
try:
|
|
206
|
+
from jupyter_matlab_proxy import config
|
|
207
|
+
except ImportError:
|
|
208
|
+
from matlab_proxy.default_configuration import config
|
|
184
209
|
|
|
185
210
|
# Get the command to start matlab-proxy
|
|
186
211
|
matlab_proxy_cmd: list = [
|
|
@@ -189,8 +214,12 @@ def _prepare_cmd_and_env_for_matlab_proxy():
|
|
|
189
214
|
config.get("extension_name"),
|
|
190
215
|
]
|
|
191
216
|
|
|
217
|
+
mwi_base_url = _construct_mwi_base_url(base_url_prefix, client_id)
|
|
218
|
+
log.info("MWI_BASE_URL : %s", mwi_base_url)
|
|
219
|
+
|
|
192
220
|
input_env: dict = {
|
|
193
221
|
"MWI_AUTH_TOKEN": secrets.token_urlsafe(32),
|
|
222
|
+
"MWI_BASE_URL": mwi_base_url,
|
|
194
223
|
}
|
|
195
224
|
|
|
196
225
|
matlab_proxy_env: dict = os.environ.copy()
|
|
@@ -199,37 +228,55 @@ def _prepare_cmd_and_env_for_matlab_proxy():
|
|
|
199
228
|
return matlab_proxy_cmd, matlab_proxy_env
|
|
200
229
|
|
|
201
230
|
|
|
202
|
-
|
|
231
|
+
def _construct_mwi_base_url(base_url_prefix: str, client_id: str):
|
|
232
|
+
# Converts to correct base url (e.g. /jupyter/, default to /jupyter/matlab/default)
|
|
233
|
+
log.debug(
|
|
234
|
+
"base_url_prefix_from_client: %s, client_id: %s", base_url_prefix, client_id
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
if base_url_prefix:
|
|
238
|
+
base_url_prefix = base_url_prefix.rstrip("/")
|
|
239
|
+
prefix = constants.MWI_BASE_URL_PREFIX.strip("/")
|
|
240
|
+
client_id = client_id.strip("/")
|
|
241
|
+
return "/".join([base_url_prefix, prefix, client_id])
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
async def _start_subprocess(cmd: list, env: dict) -> Tuple[int, str]:
|
|
203
245
|
"""
|
|
204
246
|
Initializes and starts a subprocess using the specified command and provided environment.
|
|
205
247
|
|
|
248
|
+
Args:
|
|
249
|
+
cmd (list): The command to execute the subprocess.
|
|
250
|
+
env (dict): The environment variables to set for the subprocess.
|
|
251
|
+
|
|
206
252
|
Returns:
|
|
207
|
-
Optional[int]:
|
|
253
|
+
Optional[Tuple[int, str]]: A tuple containing the process ID, the URL
|
|
254
|
+
of the server, or None if the process fails to start.
|
|
208
255
|
"""
|
|
256
|
+
|
|
209
257
|
process = None
|
|
210
|
-
|
|
258
|
+
url = None
|
|
211
259
|
|
|
212
260
|
# Get a free port and corresponding bound socket
|
|
213
261
|
with helpers.find_free_port() as (port, _):
|
|
262
|
+
log.debug("Allocated port %s", port)
|
|
263
|
+
|
|
214
264
|
env.update(
|
|
215
265
|
{
|
|
216
266
|
"MWI_APP_PORT": port,
|
|
217
|
-
"MWI_BASE_URL": mwi_base_url,
|
|
218
267
|
}
|
|
219
268
|
)
|
|
220
269
|
|
|
221
270
|
# Using loopback address so that DNS resolution doesn't add latency in Windows
|
|
222
|
-
url
|
|
223
|
-
|
|
271
|
+
url = f"http://127.0.0.1:{port}"
|
|
224
272
|
process = await _initialize_process_based_on_os_type(cmd, env)
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
return process_pid, url, mwi_base_url
|
|
273
|
+
process_pid = process.pid
|
|
274
|
+
log.debug(
|
|
275
|
+
"MATLAB proxy info: pid = %s, returncode = %s",
|
|
276
|
+
process_pid,
|
|
277
|
+
process.returncode,
|
|
278
|
+
)
|
|
279
|
+
return process_pid, url
|
|
233
280
|
|
|
234
281
|
|
|
235
282
|
async def _initialize_process_based_on_os_type(cmd, env):
|
|
@@ -240,19 +287,18 @@ async def _initialize_process_based_on_os_type(cmd, env):
|
|
|
240
287
|
environment variables. It handles both POSIX and Windows systems differently.
|
|
241
288
|
|
|
242
289
|
Args:
|
|
243
|
-
cmd (
|
|
244
|
-
env (
|
|
290
|
+
cmd (list): The command to execute the subprocess.
|
|
291
|
+
env (dict): The environment variables to set for the subprocess.
|
|
245
292
|
|
|
246
293
|
Returns:
|
|
247
|
-
|
|
248
|
-
or None if an error occurs during subprocess creation.
|
|
294
|
+
subprocess.Popen or asyncio.subprocess.Process: The process object for the started subprocess.
|
|
249
295
|
|
|
250
296
|
Raises:
|
|
251
|
-
|
|
297
|
+
exceptions.ProcessStartError: If the subprocess fails to start.
|
|
252
298
|
"""
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
299
|
+
try:
|
|
300
|
+
if mwi_sys.is_posix():
|
|
301
|
+
log.debug("Starting matlab proxy subprocess for posix")
|
|
256
302
|
return await asyncio.create_subprocess_exec(
|
|
257
303
|
*cmd,
|
|
258
304
|
env=env,
|
|
@@ -262,19 +308,15 @@ async def _initialize_process_based_on_os_type(cmd, env):
|
|
|
262
308
|
# https://github.com/ipython/ipykernel/blob/main/ipykernel/kernelbase.py#L1283
|
|
263
309
|
start_new_session=True,
|
|
264
310
|
)
|
|
265
|
-
|
|
266
|
-
log.error("Failed to create posix subprocess: %s", e)
|
|
267
|
-
return None
|
|
268
|
-
else:
|
|
269
|
-
try:
|
|
311
|
+
else:
|
|
270
312
|
log.debug("Starting matlab proxy subprocess for windows")
|
|
271
313
|
return subprocess.Popen(
|
|
272
314
|
cmd,
|
|
273
315
|
env=env,
|
|
274
316
|
)
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
317
|
+
except Exception as e:
|
|
318
|
+
log.error("Failed to create matlab-proxy subprocess: %s", e)
|
|
319
|
+
raise exceptions.ProcessStartError(extra_info=str(e)) from e
|
|
278
320
|
|
|
279
321
|
|
|
280
322
|
async def shutdown(parent_pid: str, caller_id: str, mpm_auth_token: str):
|
|
@@ -305,10 +347,10 @@ async def shutdown(parent_pid: str, caller_id: str, mpm_auth_token: str):
|
|
|
305
347
|
)
|
|
306
348
|
return
|
|
307
349
|
|
|
350
|
+
filename = f"{parent_pid}_{caller_id}"
|
|
308
351
|
try:
|
|
309
352
|
data_dir = helpers.create_and_get_proxy_manager_data_dir()
|
|
310
353
|
storage = FileRepository(data_dir)
|
|
311
|
-
filename = f"{parent_pid}_{caller_id}"
|
|
312
354
|
full_file_path, server = storage.get(filename)
|
|
313
355
|
|
|
314
356
|
if not server:
|
|
@@ -101,8 +101,11 @@ class ServerProcess:
|
|
|
101
101
|
|
|
102
102
|
# Force kill matlab-proxy and its process tree if termination
|
|
103
103
|
# via shutdown_integration endpoint fails
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
try:
|
|
105
|
+
matlab_proxy_process = psutil.Process(int(self.pid))
|
|
106
|
+
self.terminate_process_tree(matlab_proxy_process)
|
|
107
|
+
except Exception as e:
|
|
108
|
+
log.debug("Exception while terminating child processes: %s", e)
|
|
106
109
|
return None
|
|
107
110
|
|
|
108
111
|
def terminate_process_tree(self, matlab_proxy_process):
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
# Copyright 2024 The MathWorks, Inc.
|
|
1
|
+
# Copyright 2024-2025 The MathWorks, Inc.
|
|
2
2
|
|
|
3
3
|
MWI_BASE_URL_PREFIX = "/matlab/"
|
|
4
|
+
MWI_DEFAULT_MATLAB_PATH = MWI_BASE_URL_PREFIX + "default"
|
|
4
5
|
HEADER_MWI_MPM_CONTEXT = "MWI-MPM-CONTEXT"
|
|
5
6
|
HEADER_MWI_MPM_AUTH_TOKEN = "MWI-MPM-AUTH-TOKEN"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2020-
|
|
1
|
+
# Copyright 2020-2025 The MathWorks, Inc.
|
|
2
2
|
"""This file lists and exposes the environment variables which are used by proxy manager."""
|
|
3
3
|
|
|
4
4
|
import os
|
|
@@ -41,6 +41,11 @@ def get_env_name_mwi_mpm_parent_pid():
|
|
|
41
41
|
return "MWI_MPM_PARENT_PID"
|
|
42
42
|
|
|
43
43
|
|
|
44
|
+
def get_env_name_base_url_prefix():
|
|
45
|
+
"""Used to specify the base url prefix for setting base url on matlab (e.g. Jupyter base url)"""
|
|
46
|
+
return "MWI_MPM_BASE_URL_PREFIX"
|
|
47
|
+
|
|
48
|
+
|
|
44
49
|
def is_web_logging_enabled():
|
|
45
50
|
"""Returns true if the web logging is required to be enabled"""
|
|
46
51
|
return _is_env_set_to_true(get_env_name_enable_web_logging())
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Copyright 2025 The MathWorks, Inc.
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class MATLABProxyError(Exception):
|
|
5
|
+
"""Base class for all MATLAB Proxy Manager exceptions."""
|
|
6
|
+
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ProcessStartError(MATLABProxyError):
|
|
11
|
+
"""Exception thrown when MATLAB proxy process fails to start."""
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self, message="Failed to create matlab-proxy subprocess.", extra_info=None
|
|
15
|
+
):
|
|
16
|
+
self.message = message
|
|
17
|
+
self.extra_info = extra_info
|
|
18
|
+
super().__init__(message)
|
|
19
|
+
|
|
20
|
+
def __str__(self):
|
|
21
|
+
return (
|
|
22
|
+
f"{self.message} Additional info: {self.extra_info}"
|
|
23
|
+
if self.extra_info
|
|
24
|
+
else self.message
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ServerReadinessError(MATLABProxyError):
|
|
29
|
+
"""Exception thrown when MATLAB proxy server fails to become ready"""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
message="MATLAB Proxy Server unavailable: matlab-proxy-app failed to start or has timed out.",
|
|
34
|
+
extra_info=None,
|
|
35
|
+
):
|
|
36
|
+
self.message = message
|
|
37
|
+
self.extra_info = extra_info
|
|
38
|
+
super().__init__(message)
|
|
39
|
+
|
|
40
|
+
def __str__(self):
|
|
41
|
+
return (
|
|
42
|
+
f"{self.message} Additional info: {self.extra_info}"
|
|
43
|
+
if self.extra_info
|
|
44
|
+
else self.message
|
|
45
|
+
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2024 The MathWorks, Inc.
|
|
1
|
+
# Copyright 2024-2025 The MathWorks, Inc.
|
|
2
2
|
import http
|
|
3
3
|
import os
|
|
4
4
|
import socket
|
|
@@ -204,7 +204,7 @@ def poll_for_server_deletion() -> None:
|
|
|
204
204
|
Logs the status of server deletion attempts.
|
|
205
205
|
"""
|
|
206
206
|
timeout_in_seconds: int = 2
|
|
207
|
-
log.
|
|
207
|
+
log.debug("Interrupt/termination signal caught, cleaning up resources")
|
|
208
208
|
start_time = time.time()
|
|
209
209
|
|
|
210
210
|
while time.time() - start_time < timeout_in_seconds:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2024 The MathWorks, Inc.
|
|
1
|
+
# Copyright 2024-2025 The MathWorks, Inc.
|
|
2
2
|
# Helper functions to access & control the logging behavior of the app
|
|
3
3
|
|
|
4
4
|
import logging
|
|
@@ -56,6 +56,9 @@ def __set_logging_configuration():
|
|
|
56
56
|
# also print their logs at the specified level
|
|
57
57
|
logging.basicConfig(level=log_level)
|
|
58
58
|
|
|
59
|
+
# Suppress debug logs from the watchdog module
|
|
60
|
+
logging.getLogger("watchdog").setLevel(logging.WARNING)
|
|
61
|
+
|
|
59
62
|
return logger
|
|
60
63
|
|
|
61
64
|
|