matlab-proxy 0.5.3__py3-none-any.whl → 0.30.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.
- matlab_proxy/app.py +578 -205
- matlab_proxy/app_state.py +1061 -431
- matlab_proxy/constants.py +37 -0
- matlab_proxy/default_configuration.py +39 -4
- matlab_proxy/devel.py +18 -22
- matlab_proxy/gui/index.html +20 -1
- matlab_proxy/gui/static/css/index.BedVwcEg.css +10 -0
- matlab_proxy/gui/static/js/index.pQwV1obF.js +64 -0
- matlab_proxy/gui/static/media/MATLAB-env-blur.NupTbPv_.png +0 -0
- matlab_proxy/matlab/evaluateUserMatlabCode.m +51 -0
- matlab_proxy/matlab/startup.m +3 -28
- matlab_proxy/settings.py +543 -112
- matlab_proxy/util/__init__.py +187 -59
- matlab_proxy/util/cookie_jar.py +72 -0
- matlab_proxy/util/event_loop.py +28 -10
- matlab_proxy/util/list_servers.py +71 -26
- matlab_proxy/util/mw.py +16 -15
- matlab_proxy/util/mwi/download.py +136 -0
- matlab_proxy/util/mwi/embedded_connector/__init__.py +1 -1
- matlab_proxy/util/mwi/embedded_connector/helpers.py +12 -4
- matlab_proxy/util/mwi/embedded_connector/request.py +78 -12
- matlab_proxy/util/mwi/environment_variables.py +120 -27
- matlab_proxy/util/mwi/exceptions.py +63 -9
- matlab_proxy/util/mwi/logger.py +141 -27
- matlab_proxy/util/mwi/session_name.py +28 -0
- matlab_proxy/util/mwi/token_auth.py +264 -121
- matlab_proxy/util/mwi/validators.py +231 -88
- matlab_proxy/util/system.py +9 -0
- matlab_proxy/util/windows.py +32 -6
- {matlab_proxy-0.5.3.dist-info → matlab_proxy-0.30.1.dist-info}/METADATA +94 -49
- matlab_proxy-0.30.1.dist-info/RECORD +88 -0
- {matlab_proxy-0.5.3.dist-info → matlab_proxy-0.30.1.dist-info}/WHEEL +1 -2
- {matlab_proxy-0.5.3.dist-info → matlab_proxy-0.30.1.dist-info}/entry_points.txt +1 -1
- matlab_proxy_manager/README.md +85 -0
- matlab_proxy_manager/__init__.py +6 -0
- matlab_proxy_manager/lib/README.md +53 -0
- matlab_proxy_manager/lib/__init__.py +1 -0
- matlab_proxy_manager/lib/api.py +419 -0
- matlab_proxy_manager/storage/README.md +54 -0
- matlab_proxy_manager/storage/__init__.py +1 -0
- matlab_proxy_manager/storage/file_repository.py +144 -0
- matlab_proxy_manager/storage/interface.py +62 -0
- matlab_proxy_manager/storage/server.py +172 -0
- matlab_proxy_manager/utils/__init__.py +1 -0
- matlab_proxy_manager/utils/auth.py +77 -0
- matlab_proxy_manager/utils/constants.py +8 -0
- matlab_proxy_manager/utils/decorators.py +37 -0
- matlab_proxy_manager/utils/environment_variables.py +51 -0
- matlab_proxy_manager/utils/exceptions.py +45 -0
- matlab_proxy_manager/utils/helpers.py +314 -0
- matlab_proxy_manager/utils/logger.py +76 -0
- matlab_proxy_manager/web/README.md +37 -0
- matlab_proxy_manager/web/__init__.py +1 -0
- matlab_proxy_manager/web/app.py +536 -0
- matlab_proxy_manager/web/monitor.py +45 -0
- matlab_proxy_manager/web/watcher.py +65 -0
- matlab_proxy/gui/asset-manifest.json +0 -23
- matlab_proxy/gui/authorization.html +0 -115
- matlab_proxy/gui/bootstrap.3.4.1.min.css +0 -6
- matlab_proxy/gui/navbar.css +0 -8
- matlab_proxy/gui/signin.css +0 -42
- matlab_proxy/gui/static/css/main.d890078a.chunk.css +0 -13
- matlab_proxy/gui/static/css/main.d890078a.chunk.css.map +0 -1
- matlab_proxy/gui/static/js/2.13be6544.chunk.js +0 -3
- matlab_proxy/gui/static/js/2.13be6544.chunk.js.LICENSE.txt +0 -59
- matlab_proxy/gui/static/js/2.13be6544.chunk.js.map +0 -1
- matlab_proxy/gui/static/js/main.c311d854.chunk.js +0 -2
- matlab_proxy/gui/static/js/main.c311d854.chunk.js.map +0 -1
- matlab_proxy/gui/static/js/runtime-main.f70e4d5f.js +0 -2
- matlab_proxy/gui/static/js/runtime-main.f70e4d5f.js.map +0 -1
- matlab_proxy/gui/static/media/arrow.0c2968b9.svg +0 -4
- matlab_proxy/gui/static/media/feedback.6e8d50eb.svg +0 -1
- matlab_proxy/gui/static/media/gripper.9defbc5e.svg +0 -1
- matlab_proxy/gui/static/media/help.15e5bfab.svg +0 -1
- matlab_proxy/gui/static/media/ico-header-contact-hover.0958c442.svg +0 -17
- matlab_proxy/gui/static/media/ico-header-contact.ae9169c8.svg +0 -17
- matlab_proxy/gui/static/media/restart.7987508a.svg +0 -1
- matlab_proxy/gui/static/media/sign-out.08356b67.svg +0 -1
- matlab_proxy/gui/static/media/start.50c4596f.svg +0 -1
- matlab_proxy/gui/static/media/stop.30c9a9ab.svg +0 -1
- matlab_proxy/gui/static/media/terminate.7ea1363e.svg +0 -1
- matlab_proxy/gui/token.html +0 -123
- matlab_proxy-0.5.3.dist-info/RECORD +0 -84
- matlab_proxy-0.5.3.dist-info/top_level.txt +0 -1
- /matlab_proxy/gui/static/media/{glyphicons-halflings-regular.82b1212e.woff → glyphicons-halflings-regular.BKjkU69z.woff} +0 -0
- /matlab_proxy/gui/static/media/{glyphicons-halflings-regular.5be1347c.eot → glyphicons-halflings-regular.BUJKDMgK.eot} +0 -0
- /matlab_proxy/gui/static/media/{glyphicons-halflings-regular.060b2710.svg → glyphicons-halflings-regular.CSehLiBc.svg} +0 -0
- /matlab_proxy/gui/static/media/{glyphicons-halflings-regular.4692b9ec.ttf → glyphicons-halflings-regular.DrwTMapi.ttf} +0 -0
- /matlab_proxy/gui/static/media/{glyphicons-halflings-regular.be810be3.woff2 → glyphicons-halflings-regular.DzqM6ju8.woff2} +0 -0
- /matlab_proxy/gui/static/media/{ico-header-account-hover.89438e91.svg → ico-header-account-hover.-jQHo6Wx.svg} +0 -0
- /matlab_proxy/gui/static/media/{ico-header-account.86b10d7b.svg → ico-header-account.CJCFoo5a.svg} +0 -0
- /matlab_proxy/gui/static/media/{ico-sprite.cbdb66c0.png → ico-sprite.DXGLgzq9.png} +0 -0
- /matlab_proxy/gui/static/media/{mathworks-eps.4d20e0ee.ttf → mathworks-eps.CGNQALa9.ttf} +0 -0
- /matlab_proxy/gui/static/media/{mathworks-eps.df1428df.svg → mathworks-eps.DrkCtQtG.svg} +0 -0
- /matlab_proxy/gui/static/media/{mathworks-eps.e5c41e84.woff → mathworks-eps.Ds7lQbql.woff} +0 -0
- /matlab_proxy/gui/static/media/{mathworks-pictograms.3fc6513a.woff → mathworks-pictograms.BdqxEfBR.woff} +0 -0
- /matlab_proxy/gui/static/media/{mathworks-pictograms.f6f087b0.svg → mathworks-pictograms.CCLweoD4.svg} +0 -0
- /matlab_proxy/gui/static/media/{mathworks-pictograms.6e128c0e.ttf → mathworks-pictograms.DZhFdRSm.ttf} +0 -0
- /matlab_proxy/gui/static/media/{mathworks.80a3218e.svg → mathworks.C-qsbhDy.svg} +0 -0
- /matlab_proxy/gui/static/media/{mathworks.c422935b.ttf → mathworks.Ceplx86V.ttf} +0 -0
- /matlab_proxy/gui/static/media/{mathworks.37a563ef.woff → mathworks.D08X1Vp8.woff} +0 -0
- /matlab_proxy/gui/static/media/{trigger-error.3f1c4ef2.svg → trigger-error.QEdsGL-m.svg} +0 -0
- /matlab_proxy/gui/static/media/{trigger-ok.7b9c238b.svg → trigger-ok.Dzg8OIrk.svg} +0 -0
- {matlab_proxy-0.5.3.dist-info → matlab_proxy-0.30.1.dist-info/licenses}/LICENSE.md +0 -0
|
@@ -1,30 +1,36 @@
|
|
|
1
|
-
# Copyright
|
|
2
|
-
"""This file contains validators for various runtime
|
|
3
|
-
A validator is defined as a function which verifies the input and
|
|
4
|
-
returns it unchanged if validation passes.
|
|
1
|
+
# Copyright 2020-2025 The MathWorks, Inc.
|
|
2
|
+
"""This file contains validators for various runtime artifacts.
|
|
3
|
+
A validator is defined as a function which verifies the input and
|
|
4
|
+
returns it unchanged if validation passes.
|
|
5
5
|
Returning inputs allows validators to be used inline with the input.
|
|
6
6
|
|
|
7
|
-
Example:
|
|
7
|
+
Example:
|
|
8
8
|
Original code: if( input ):
|
|
9
9
|
With validator: if (valid(input)):
|
|
10
10
|
|
|
11
11
|
Exceptions are thrown to signal failure.
|
|
12
12
|
"""
|
|
13
|
+
|
|
13
14
|
import errno
|
|
15
|
+
import math
|
|
14
16
|
import os
|
|
15
17
|
import socket
|
|
16
|
-
import
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import List
|
|
17
20
|
|
|
18
21
|
import matlab_proxy
|
|
19
|
-
import
|
|
22
|
+
from matlab_proxy import util
|
|
23
|
+
from matlab_proxy.constants import VERSION_INFO_FILE_NAME
|
|
24
|
+
from matlab_proxy.util import system
|
|
20
25
|
|
|
21
26
|
from . import environment_variables as mwi_env
|
|
22
27
|
from . import logger as mwi_logger
|
|
28
|
+
from .exceptions import FatalError, MatlabInstallError
|
|
23
29
|
|
|
24
30
|
logger = mwi_logger.get()
|
|
25
31
|
|
|
26
32
|
|
|
27
|
-
def validate_mlm_license_file(
|
|
33
|
+
def validate_mlm_license_file(nlm_connections_str):
|
|
28
34
|
"""Validates and returns input if it passes validation.
|
|
29
35
|
Throws exception when validation fails.
|
|
30
36
|
The connection string should be in the form of port@hostname
|
|
@@ -39,44 +45,65 @@ def validate_mlm_license_file(nlm_conn_str):
|
|
|
39
45
|
Returns:
|
|
40
46
|
String: Returns the same argument passed to this function if its valid.
|
|
41
47
|
"""
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
nlm_connections_str can either be a valid path to a file or a
|
|
51
|
+
string with comma seperated values, each of the form port@hostname
|
|
52
|
+
|
|
53
|
+
Some valid nlm_connections_str values are:
|
|
54
|
+
1) port@hostname
|
|
55
|
+
2) port@hostname,
|
|
56
|
+
3) port1@hostname1,port2@hostname2
|
|
57
|
+
4) port1@hostname1,port2@hostname2,
|
|
58
|
+
5) port1@hostname1,port2@hostname2,port3@hostname3,
|
|
59
|
+
"""
|
|
42
60
|
import re
|
|
43
61
|
|
|
44
62
|
from .exceptions import NetworkLicensingError
|
|
45
63
|
|
|
46
|
-
if
|
|
64
|
+
if not nlm_connections_str:
|
|
65
|
+
# Handles empty strings and None values
|
|
47
66
|
return None
|
|
48
67
|
|
|
49
|
-
# TODO: The JS validation of this setting does not allow file path locations
|
|
50
|
-
# The JS validation occurs before reaching the set_licensing_info endpoint.
|
|
51
|
-
|
|
52
68
|
# Regular expression to match port@hostname,
|
|
53
69
|
# where port is any number and hostname is alphanumeric
|
|
54
70
|
# regex = Start of Line, Any number of 0-9 digits , @, any number of nonwhite space characters with "- _ ." allowed
|
|
55
71
|
# "^[0-9]+[@](\w|\_|\-|\.)+$"
|
|
56
|
-
# Server triad is of the form : port@host1,port@host2,port@host3
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
72
|
+
# Server triad is of the form : port@host1 or port@host1,port@host2,port@host3
|
|
73
|
+
nlm_connection_str_regex = r"(^[0-9]+[@](\w|\_|\-|\.)+$)"
|
|
74
|
+
error_message = (
|
|
75
|
+
f"MLM_LICENSE_FILE validation failed for {nlm_connections_str}. "
|
|
76
|
+
f"If set, the MLM_LICENSE_FILE environment variable must contain server names (each of the form port@hostname) separated by ':' on unix or ';' on windows(server triads however must be comma seperated)"
|
|
77
|
+
f" OR path to a valid license file."
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
seperator = system.get_mlm_license_file_seperator()
|
|
81
|
+
nlm_connection_strs = re.split(f"{seperator}|,", nlm_connections_str)
|
|
82
|
+
|
|
83
|
+
logger.debug(
|
|
84
|
+
"Validating individual parts of the environment variable MLM_LICENSE_FILE"
|
|
85
|
+
)
|
|
86
|
+
for nlm_connection_str in nlm_connection_strs:
|
|
87
|
+
# Individual parts of the MLM_LICENSE_FILE can either be a valid path to a license file or a server name.
|
|
88
|
+
|
|
89
|
+
if os.path.isfile(nlm_connection_str):
|
|
70
90
|
logger.info(
|
|
71
|
-
f"
|
|
91
|
+
f"{nlm_connections_str} is a path to a file. MATLAB will attempt to use it."
|
|
72
92
|
)
|
|
73
|
-
else:
|
|
74
|
-
logger.info(
|
|
75
|
-
f"MLM_LICENSE_FILE with value: {nlm_conn_str} is a license server, MATLAB will attempt to connect to it."
|
|
76
|
-
)
|
|
77
93
|
|
|
78
|
-
|
|
79
|
-
|
|
94
|
+
else:
|
|
95
|
+
match = re.search(nlm_connection_str_regex, nlm_connection_str)
|
|
96
|
+
|
|
97
|
+
if match:
|
|
98
|
+
logger.debug(f"Successfully validated {nlm_connection_str}")
|
|
99
|
+
else:
|
|
100
|
+
logger.error(f"Failed to validate:{nlm_connection_str}")
|
|
101
|
+
logger.error(
|
|
102
|
+
"NLM_info is not of the form port@hostname or a valid path to a file"
|
|
103
|
+
)
|
|
104
|
+
raise NetworkLicensingError(error_message)
|
|
105
|
+
|
|
106
|
+
return nlm_connections_str
|
|
80
107
|
|
|
81
108
|
|
|
82
109
|
def validate_app_port_is_free(port):
|
|
@@ -107,10 +134,9 @@ def validate_app_port_is_free(port):
|
|
|
107
134
|
return port
|
|
108
135
|
except socket.error as e:
|
|
109
136
|
if e.errno == errno.EADDRINUSE:
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
)
|
|
113
|
-
sys.exit(1)
|
|
137
|
+
error_message = f"The port {port} is not available. Please set another value for the environment variable {mwi_env.get_env_name_app_port()}"
|
|
138
|
+
logger.error(error_message)
|
|
139
|
+
raise FatalError(error_message)
|
|
114
140
|
else:
|
|
115
141
|
raise e
|
|
116
142
|
|
|
@@ -134,10 +160,9 @@ def validate_base_url(base_url):
|
|
|
134
160
|
|
|
135
161
|
else:
|
|
136
162
|
if not base_url.startswith("/"):
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
)
|
|
140
|
-
sys.exit(1)
|
|
163
|
+
error_message = f'The value of environment variable {mwi_env.get_env_name_base_url()} must start with "/" '
|
|
164
|
+
logger.error(error_message)
|
|
165
|
+
raise FatalError(error_message)
|
|
141
166
|
|
|
142
167
|
validated_base_url = base_url[:-1] if base_url.endswith("/") else base_url
|
|
143
168
|
|
|
@@ -154,30 +179,31 @@ def validate_env_config(config):
|
|
|
154
179
|
Returns:
|
|
155
180
|
Dict: Containing data specific to the environment in which MATLAB proxy is being used in.
|
|
156
181
|
"""
|
|
157
|
-
|
|
182
|
+
from matlab_proxy.default_configuration import get_required_config
|
|
183
|
+
|
|
184
|
+
available_configs: dict = __get_configs()
|
|
158
185
|
config = config.lower()
|
|
159
186
|
|
|
160
187
|
# Check if supplied config is present in the available configs
|
|
161
188
|
if config in available_configs:
|
|
162
|
-
# Check if all keys are present in the supplied config
|
|
163
|
-
default_config_keys = available_configs[
|
|
164
|
-
matlab_proxy.get_default_config_name()
|
|
165
|
-
].keys()
|
|
166
189
|
env_config = available_configs[config]
|
|
190
|
+
required_keys = get_required_config()
|
|
167
191
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
192
|
+
# Check if all required keys are present in the supplied config
|
|
193
|
+
valid = all(key in env_config for key in required_keys)
|
|
194
|
+
if not valid:
|
|
195
|
+
error_message = (
|
|
196
|
+
f"Required key/s missing in the provided {config} configuration"
|
|
197
|
+
)
|
|
198
|
+
logger.error(error_message)
|
|
199
|
+
raise FatalError(error_message)
|
|
172
200
|
|
|
173
|
-
logger.debug(
|
|
201
|
+
logger.debug("Successfully validated provided %s configuration", config)
|
|
174
202
|
return env_config
|
|
175
203
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
)
|
|
180
|
-
sys.exit(1)
|
|
204
|
+
error_message = f"{config} is not a valid config. Available configs are : {list(available_configs.keys())}"
|
|
205
|
+
logger.error(error_message)
|
|
206
|
+
raise FatalError(error_message)
|
|
181
207
|
|
|
182
208
|
|
|
183
209
|
def __get_configs():
|
|
@@ -188,56 +214,173 @@ def __get_configs():
|
|
|
188
214
|
Dict: Contains all the values present in 'matlab_web_desktop_configs' entry_point from all the packages
|
|
189
215
|
installed in the current environment.
|
|
190
216
|
"""
|
|
217
|
+
import importlib.metadata as metadata
|
|
218
|
+
|
|
219
|
+
matlab_proxy_eps = metadata.entry_points(group=matlab_proxy.get_entrypoint_name())
|
|
191
220
|
configs = {}
|
|
192
|
-
for entry_point in
|
|
193
|
-
matlab_proxy.get_entrypoint_name()
|
|
194
|
-
):
|
|
221
|
+
for entry_point in matlab_proxy_eps:
|
|
195
222
|
configs[entry_point.name.lower()] = entry_point.load()
|
|
196
223
|
|
|
197
224
|
return configs
|
|
198
225
|
|
|
199
226
|
|
|
200
|
-
def
|
|
227
|
+
def validate_ssl_file(ssl_file, env_name):
|
|
201
228
|
"""Ensures that its a valid readable file"""
|
|
202
229
|
|
|
203
230
|
# Empty strings are valid inputs
|
|
204
|
-
if
|
|
205
|
-
|
|
206
|
-
if not os.path.isfile(a_ssl_cert_file):
|
|
207
|
-
logger.error(f"MWI_SSL_CERT_FILE is not a valid file: {a_ssl_cert_file}")
|
|
208
|
-
sys.exit(1)
|
|
209
|
-
|
|
210
|
-
# string is either empty, or is a valid file on disk
|
|
211
|
-
return a_ssl_cert_file
|
|
231
|
+
if not ssl_file:
|
|
232
|
+
return None
|
|
212
233
|
|
|
234
|
+
# String is not empty, check to see if the file exists
|
|
235
|
+
if not os.path.isfile(ssl_file):
|
|
236
|
+
error_message = f"{env_name} is not a valid file: {ssl_file}"
|
|
237
|
+
logger.error(error_message)
|
|
238
|
+
raise FatalError(error_message)
|
|
213
239
|
|
|
214
|
-
|
|
215
|
-
|
|
240
|
+
# string is a valid file on disk
|
|
241
|
+
return ssl_file
|
|
216
242
|
|
|
217
|
-
if a_ssl_cert_file is None and a_ssl_key_file is None:
|
|
218
|
-
# Both values are None, this is acceptable.
|
|
219
|
-
return a_ssl_key_file, a_ssl_cert_file
|
|
220
243
|
|
|
221
|
-
|
|
244
|
+
def validate_ssl_key_and_cert_file(ssl_key_file, ssl_cert_file):
|
|
245
|
+
"""Validates that provided SSL files are valid readable files"""
|
|
246
|
+
env_name_ssl_cert_file = mwi_env.get_env_name_ssl_cert_file()
|
|
247
|
+
env_name_ssl_key_file = mwi_env.get_env_name_ssl_key_file()
|
|
222
248
|
|
|
223
|
-
|
|
224
|
-
|
|
249
|
+
if not ssl_cert_file and not ssl_key_file:
|
|
250
|
+
# Both values are falsy, this is acceptable and signify that HTTPS communication is disabled.
|
|
251
|
+
return None, None
|
|
225
252
|
|
|
226
|
-
|
|
227
|
-
logger.error(f"MWI_SSL_CERT_FILE must be provided to use the MWI_SSL_KEY_FILE")
|
|
228
|
-
sys.exit(1)
|
|
253
|
+
# Implies at least one value is not falsy.
|
|
229
254
|
|
|
230
|
-
|
|
255
|
+
# Validating cert file- Cert file is either empty or valid file.
|
|
256
|
+
cert_file = validate_ssl_file(
|
|
257
|
+
ssl_file=ssl_cert_file, env_name=env_name_ssl_cert_file
|
|
258
|
+
)
|
|
259
|
+
if not cert_file:
|
|
260
|
+
error_message = f"{env_name_ssl_cert_file} must be provided to use the {env_name_ssl_key_file}"
|
|
261
|
+
logger.error(error_message)
|
|
262
|
+
raise FatalError(error_message)
|
|
263
|
+
|
|
264
|
+
# Validating key file
|
|
265
|
+
key_file = validate_ssl_file(ssl_file=ssl_key_file, env_name=env_name_ssl_key_file)
|
|
266
|
+
if not ssl_key_file:
|
|
231
267
|
logger.info(
|
|
232
|
-
f"
|
|
268
|
+
f"{env_name_ssl_key_file} is not provided, ensure that your {env_name_ssl_cert_file} : '{cert_file}' contains a private key"
|
|
233
269
|
)
|
|
234
270
|
|
|
235
|
-
if a_ssl_key_file:
|
|
236
|
-
if not os.path.isfile(a_ssl_key_file):
|
|
237
|
-
logger.error(f"MWI_SSL_KEY_FILE is not a valid file: {a_ssl_key_file}")
|
|
238
|
-
sys.exit(1)
|
|
239
|
-
|
|
240
271
|
logger.info(
|
|
241
|
-
f"SSL Keys provided were:
|
|
272
|
+
f"SSL Keys provided were: {env_name_ssl_cert_file}: {cert_file} & {env_name_ssl_key_file}: {key_file}"
|
|
242
273
|
)
|
|
243
|
-
return
|
|
274
|
+
return key_file, cert_file
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def validate_use_existing_licensing(use_existing_license):
|
|
278
|
+
"""Returns true if use_existing_license is true
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
use_existing_license (str): value from the environment variable MWI_USE_EXISTING_LICENSE
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
bool: if use_existing_license is set to true
|
|
285
|
+
"""
|
|
286
|
+
return True if use_existing_license.casefold() == "true" else False
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def __validate_if_paths_exist(paths: List[Path]):
|
|
290
|
+
"""Validates if paths of directories or files exists on the file system.
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
paths ([pathlib.Path]): List of pathlib.Path's to directories or files
|
|
294
|
+
|
|
295
|
+
Raises:
|
|
296
|
+
OSError: When an invalid path is supplied
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
[pathlib.Path] | None: [pathlib.Path] if valid paths are supplied else None
|
|
300
|
+
"""
|
|
301
|
+
for path in paths:
|
|
302
|
+
if not util.is_valid_path(path):
|
|
303
|
+
raise OSError(f"Supplied invalid path:{path}")
|
|
304
|
+
|
|
305
|
+
return paths
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def validate_matlab_root_path(matlab_root: Path, is_custom_matlab_root: bool):
|
|
309
|
+
"""Validate if path supplied is MATLAB_ROOT by checking for the existence of VersionInfo.xml file
|
|
310
|
+
at matlab_root.
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
path (pathlib.Path): path to MATLAB root
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
pathlib.Path | None: pathlib.Path if a valid path to MATLAB root is supplied else None
|
|
317
|
+
|
|
318
|
+
Raises:
|
|
319
|
+
MatlabInstallError
|
|
320
|
+
"""
|
|
321
|
+
|
|
322
|
+
# When Custom MATLAB root is provided, validate the existence of the
|
|
323
|
+
# VersionInfo.xml file at the specified path else, its optional (for matlab wrapper usecase)
|
|
324
|
+
custom_matlab_root_warn_str = f"Edit the environment variable {mwi_env.get_env_name_custom_matlab_root()} to the correct path, and restart matlab-proxy. "
|
|
325
|
+
|
|
326
|
+
try:
|
|
327
|
+
__validate_if_paths_exist([matlab_root])
|
|
328
|
+
logger.debug(
|
|
329
|
+
f"MATLAB root path: {matlab_root} exists, continuing to verify its validity..."
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
except OSError as exc:
|
|
333
|
+
logger.error(". ".join(exc.args))
|
|
334
|
+
raise MatlabInstallError(
|
|
335
|
+
custom_matlab_root_warn_str if is_custom_matlab_root else ""
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
version_info_file_path = matlab_root / VERSION_INFO_FILE_NAME
|
|
339
|
+
|
|
340
|
+
if not version_info_file_path.is_file():
|
|
341
|
+
warn_str = f"Unable to locate {VERSION_INFO_FILE_NAME} at {matlab_root}"
|
|
342
|
+
# If VersionInfo.xml file is missing when a custom MATLAB root is provided, then
|
|
343
|
+
# raise an error with a detailed message
|
|
344
|
+
if is_custom_matlab_root:
|
|
345
|
+
log_error_string = custom_matlab_root_warn_str + warn_str
|
|
346
|
+
raise MatlabInstallError(log_error_string)
|
|
347
|
+
|
|
348
|
+
else:
|
|
349
|
+
# No VersionInfo.xml file is present and its not a custom MATLAB root, implies a matlab wrapper is
|
|
350
|
+
# being used, so warn the user and return None as MATLAB root could not be determined
|
|
351
|
+
logger.warning(warn_str)
|
|
352
|
+
return None
|
|
353
|
+
|
|
354
|
+
return matlab_root
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def validate_idle_timeout(timeout):
|
|
358
|
+
"""Validate if IDLE timeout for matlab-proxy
|
|
359
|
+
|
|
360
|
+
Args:
|
|
361
|
+
timeout (None | int): IDLE timeout for shutdown of matlab-proxy.
|
|
362
|
+
|
|
363
|
+
Raises:
|
|
364
|
+
ValueError: If a non-numerical value is supplied other than None.
|
|
365
|
+
|
|
366
|
+
Returns:
|
|
367
|
+
None | int : The timeout value.
|
|
368
|
+
"""
|
|
369
|
+
if not timeout:
|
|
370
|
+
return timeout
|
|
371
|
+
|
|
372
|
+
try:
|
|
373
|
+
# Convert timeout to seconds
|
|
374
|
+
timeout = math.ceil(float(timeout) * 60)
|
|
375
|
+
|
|
376
|
+
if timeout <= 0:
|
|
377
|
+
raise ValueError
|
|
378
|
+
|
|
379
|
+
logger.info(f"MATLAB IDLE timeout set to {timeout} seconds")
|
|
380
|
+
return timeout
|
|
381
|
+
|
|
382
|
+
except ValueError:
|
|
383
|
+
logger.warning(
|
|
384
|
+
f"Invalid value supplied for {mwi_env.get_env_name_shutdown_on_idle_timeout()}: {timeout}. Continuing without any IDLE timeout."
|
|
385
|
+
)
|
|
386
|
+
return None
|
matlab_proxy/util/system.py
CHANGED
|
@@ -63,3 +63,12 @@ def get_supported_termination_signals():
|
|
|
63
63
|
if is_posix()
|
|
64
64
|
else [signal.SIGINT, signal.SIGTERM]
|
|
65
65
|
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_mlm_license_file_seperator():
|
|
69
|
+
"""Returns OS specific seperator for MLM_LICENSE_FILE environment variable
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
str: OS specific seperator for MLM_LICENSE_FILE
|
|
73
|
+
"""
|
|
74
|
+
return ":" if is_posix() else ";"
|
matlab_proxy/util/windows.py
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
# Copyright 2022 The MathWorks, Inc.
|
|
1
|
+
# Copyright 2022-2024 The MathWorks, Inc.
|
|
2
2
|
import asyncio
|
|
3
3
|
|
|
4
4
|
from matlab_proxy import util
|
|
5
5
|
from matlab_proxy.util import mwi
|
|
6
6
|
from matlab_proxy.util.mwi import environment_variables as mwi_env
|
|
7
|
+
from matlab_proxy.util.mwi.exceptions import (
|
|
8
|
+
UIVisibleFatalError,
|
|
9
|
+
)
|
|
7
10
|
|
|
8
11
|
""" This file contains methods specific to non-posix / windows OS.
|
|
9
12
|
"""
|
|
@@ -43,23 +46,28 @@ async def start_matlab(matlab_cmd, matlab_env):
|
|
|
43
46
|
Returns:
|
|
44
47
|
psutil.Process(): The MATLAB process object.
|
|
45
48
|
"""
|
|
49
|
+
import psutil
|
|
46
50
|
|
|
51
|
+
# The stdout is used to suppress the MATLAB outputs from being shown in the terminal.
|
|
52
|
+
# We set it to DEVNULL instead of PIPE because PIPE has a limited buffer size and can
|
|
53
|
+
# block the process if the output exceeds the buffer limit.
|
|
47
54
|
intermediate_proc = await asyncio.create_subprocess_exec(
|
|
48
55
|
*matlab_cmd,
|
|
49
56
|
env=matlab_env,
|
|
57
|
+
stdout=asyncio.subprocess.DEVNULL,
|
|
50
58
|
stderr=asyncio.subprocess.STDOUT,
|
|
51
59
|
)
|
|
52
60
|
|
|
53
61
|
# In testing mode, the devel.py file is run, which is the fake MATLAB server.
|
|
54
62
|
# So, there is no need to check for an intermediate process when testing and can return
|
|
55
63
|
# the same process as a psutil.Process() object.
|
|
56
|
-
if mwi_env.is_testing_mode_enabled():
|
|
57
|
-
import psutil
|
|
58
|
-
|
|
64
|
+
if mwi_env.is_testing_mode_enabled() or mwi_env.is_development_mode_enabled():
|
|
59
65
|
proc = psutil.Process(intermediate_proc.pid)
|
|
60
66
|
|
|
61
67
|
return proc
|
|
62
68
|
|
|
69
|
+
matlab = None
|
|
70
|
+
|
|
63
71
|
try:
|
|
64
72
|
children = util.get_child_processes(intermediate_proc)
|
|
65
73
|
|
|
@@ -74,8 +82,26 @@ async def start_matlab(matlab_cmd, matlab_env):
|
|
|
74
82
|
"MATLAB.exe" == matlab.name()
|
|
75
83
|
), "Expecting the child process name to be MATLAB.exe"
|
|
76
84
|
|
|
77
|
-
except AssertionError as err:
|
|
85
|
+
except (AssertionError, UIVisibleFatalError) as err:
|
|
78
86
|
raise err
|
|
79
87
|
|
|
88
|
+
except psutil.NoSuchProcess:
|
|
89
|
+
# We reach here when the intermediate process launched by matlab-proxy died
|
|
90
|
+
# before we can query for its child processes. Hence, to find the actual MATLAB
|
|
91
|
+
# process, we check all the processes name and parent process id. Ideally, this
|
|
92
|
+
# approach should work in all cases unless MATLAB itself has exited / crashed.
|
|
93
|
+
logger.debug(
|
|
94
|
+
"Intermediate process not found. Querying all process to find MATLAB"
|
|
95
|
+
)
|
|
96
|
+
for process in psutil.process_iter():
|
|
97
|
+
if (
|
|
98
|
+
process.name() == "MATLAB.exe"
|
|
99
|
+
and process.ppid() == intermediate_proc.pid
|
|
100
|
+
):
|
|
101
|
+
matlab = process
|
|
102
|
+
break
|
|
103
|
+
|
|
104
|
+
assert matlab != None, "MATLAB Process ID not found"
|
|
105
|
+
|
|
80
106
|
# Return the actual MATLAB processes
|
|
81
|
-
return
|
|
107
|
+
return matlab
|