thestage 0.5.46__py3-none-any.whl → 0.5.471__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.
- thestage/.env +5 -0
- thestage/__init__.py +2 -1
- thestage/cli_command.py +56 -0
- thestage/cli_command_helper.py +51 -0
- thestage/config/config_storage.py +5 -0
- thestage/controllers/base_controller.py +19 -15
- thestage/controllers/config_controller.py +30 -38
- thestage/controllers/container_controller.py +43 -79
- thestage/controllers/instance_controller.py +23 -40
- thestage/controllers/project_controller.py +95 -184
- thestage/controllers/utils_controller.py +12 -8
- thestage/debug_tests.py +12 -0
- thestage/entities/container.py +0 -5
- thestage/entities/rented_instance.py +0 -5
- thestage/entities/self_hosted_instance.py +0 -2
- thestage/helpers/error_handler.py +14 -14
- thestage/helpers/exception_hook.py +14 -0
- thestage/helpers/logger/app_logger.py +3 -4
- thestage/main.py +25 -13
- thestage/services/abstract_service.py +0 -40
- thestage/services/app_config_service.py +7 -6
- thestage/services/clients/.DS_Store +0 -0
- thestage/services/clients/thestage_api/api_client.py +54 -68
- thestage/services/clients/thestage_api/core/api_client_core.py +92 -9
- thestage/services/clients/thestage_api/dtos/container_response.py +1 -1
- thestage/services/clients/thestage_api/dtos/inference_simulator_model_response.py +1 -1
- thestage/services/clients/thestage_api/dtos/inference_simulator_response.py +1 -1
- thestage/services/clients/thestage_api/dtos/instance_rented_response.py +1 -1
- thestage/services/clients/thestage_api/dtos/selfhosted_instance_response.py +1 -1
- thestage/services/clients/thestage_api/dtos/task_controller/task_status_localized_map_response.py +1 -1
- thestage/services/clients/thestage_api/dtos/validate_token_response.py +11 -0
- thestage/services/config_provider/config_provider.py +75 -47
- thestage/services/connect/connect_service.py +11 -22
- thestage/services/container/container_service.py +6 -23
- thestage/services/core_files/config_entity.py +7 -1
- thestage/services/filesystem_service.py +2 -2
- thestage/services/instance/instance_service.py +12 -26
- thestage/services/logging/logging_service.py +17 -45
- thestage/services/project/project_service.py +33 -72
- thestage/services/remote_server_service.py +3 -4
- thestage/services/service_factory.py +21 -27
- thestage/services/validation_service.py +14 -9
- {thestage-0.5.46.dist-info → thestage-0.5.471.dist-info}/METADATA +3 -4
- {thestage-0.5.46.dist-info → thestage-0.5.471.dist-info}/RECORD +47 -41
- {thestage-0.5.46.dist-info → thestage-0.5.471.dist-info}/WHEEL +1 -1
- thestage/exceptions/http_error_exception.py +0 -12
- thestage/services/clients/thestage_api/core/api_client_abstract.py +0 -91
- {thestage-0.5.46.dist-info → thestage-0.5.471.dist-info}/LICENSE.txt +0 -0
- {thestage-0.5.46.dist-info → thestage-0.5.471.dist-info}/entry_points.txt +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from typing import Optional, List, Tuple, Dict, Iterator
|
|
2
2
|
|
|
3
3
|
import httpx
|
|
4
|
-
import requests
|
|
5
4
|
|
|
6
5
|
from thestage.helpers.error_handler import error_handler
|
|
7
6
|
from thestage.services.clients.thestage_api.core.api_client_core import TheStageApiClientCore
|
|
@@ -34,11 +33,8 @@ from thestage.services.clients.thestage_api.dtos.inference_simulator_model_respo
|
|
|
34
33
|
InferenceSimulatorModelStatusMapperResponse
|
|
35
34
|
from thestage.services.clients.thestage_api.dtos.inference_simulator_response import \
|
|
36
35
|
InferenceSimulatorStatusMapperResponse
|
|
37
|
-
from thestage.services.clients.thestage_api.dtos.logging_controller.docker_container_log_stream_request import \
|
|
38
|
-
DockerContainerLogStreamRequest
|
|
39
36
|
from thestage.services.clients.thestage_api.dtos.logging_controller.log_polling_request import LogPollingRequest
|
|
40
37
|
from thestage.services.clients.thestage_api.dtos.logging_controller.log_polling_response import LogPollingResponse
|
|
41
|
-
from thestage.services.clients.thestage_api.dtos.logging_controller.task_log_stream_request import TaskLogStreamRequest
|
|
42
38
|
from thestage.services.clients.thestage_api.dtos.logging_controller.user_logs_query_request import UserLogsQueryRequest
|
|
43
39
|
from thestage.services.clients.thestage_api.dtos.logging_controller.user_logs_query_response import \
|
|
44
40
|
UserLogsQueryResponse
|
|
@@ -89,19 +85,25 @@ from thestage.services.clients.thestage_api.dtos.instance_rented_response import
|
|
|
89
85
|
InstanceRentedDto, InstanceRentedItemResponse, InstanceRentedBusinessStatusMapperResponse
|
|
90
86
|
|
|
91
87
|
from thestage.services.clients.thestage_api.dtos.base_response import TheStageBaseResponse
|
|
92
|
-
from thestage.services.
|
|
88
|
+
from thestage.services.config_provider.config_provider import ConfigProvider
|
|
93
89
|
from thestage.services.project.dto.inference_simulator_dto import InferenceSimulatorDto
|
|
94
90
|
from thestage.services.project.dto.inference_simulator_model_dto import InferenceSimulatorModelDto
|
|
95
91
|
from thestage.services.task.dto.task_dto import TaskDto
|
|
96
92
|
|
|
97
93
|
|
|
98
94
|
class TheStageApiClient(TheStageApiClientCore):
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
__config_provider: ConfigProvider = None
|
|
96
|
+
|
|
97
|
+
def __init__(
|
|
98
|
+
self,
|
|
99
|
+
config_provider: ConfigProvider,
|
|
100
|
+
):
|
|
101
|
+
# TODO this is super bullshit, remove all abstract classes
|
|
102
|
+
super().__init__(url=config_provider.get_config().main.thestage_api_url)
|
|
103
|
+
self.__config_provider = config_provider
|
|
101
104
|
|
|
102
105
|
def get_task(
|
|
103
106
|
self,
|
|
104
|
-
token: str,
|
|
105
107
|
task_id: int,
|
|
106
108
|
) -> Optional[TaskViewResponse]:
|
|
107
109
|
data = {
|
|
@@ -112,7 +114,7 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
112
114
|
method='POST',
|
|
113
115
|
url='/user-api/v1/task/view',
|
|
114
116
|
data=data,
|
|
115
|
-
token=
|
|
117
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
116
118
|
)
|
|
117
119
|
|
|
118
120
|
result = TaskViewResponse.model_validate(response) if response else None
|
|
@@ -120,7 +122,6 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
120
122
|
|
|
121
123
|
def get_task_list_for_project(
|
|
122
124
|
self,
|
|
123
|
-
token: str,
|
|
124
125
|
project_slug: str,
|
|
125
126
|
page: int = 1,
|
|
126
127
|
limit: int = 10,
|
|
@@ -139,7 +140,7 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
139
140
|
method='POST',
|
|
140
141
|
url='/user-api/v1/task/list-for-project',
|
|
141
142
|
data=request.model_dump(),
|
|
142
|
-
token=
|
|
143
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
143
144
|
)
|
|
144
145
|
|
|
145
146
|
result = TaskListForProjectResponse.model_validate(response) if response else None
|
|
@@ -147,7 +148,6 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
147
148
|
|
|
148
149
|
def get_inference_simulator_list_for_project(
|
|
149
150
|
self,
|
|
150
|
-
token: str,
|
|
151
151
|
project_slug: str,
|
|
152
152
|
statuses: List[str] = [],
|
|
153
153
|
page: int = 1,
|
|
@@ -168,14 +168,13 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
168
168
|
method='POST',
|
|
169
169
|
url='/user-api/v1/project/inference-simulator/list',
|
|
170
170
|
data=request.model_dump(),
|
|
171
|
-
token=
|
|
171
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
172
172
|
)
|
|
173
173
|
result = InferenceSimulatorListForProjectResponse.model_validate(response) if response else None
|
|
174
174
|
return result.inferenceSimulators if result and result.is_success else None
|
|
175
175
|
|
|
176
176
|
def get_inference_simulator_model_list_for_project(
|
|
177
177
|
self,
|
|
178
|
-
token: str,
|
|
179
178
|
project_slug: str,
|
|
180
179
|
statuses: Optional[List[str]] = None,
|
|
181
180
|
page: int = 1,
|
|
@@ -196,14 +195,13 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
196
195
|
method='POST',
|
|
197
196
|
url='/user-api/v1/project/inference-simulator-model/list',
|
|
198
197
|
data=request.model_dump(),
|
|
199
|
-
token=
|
|
198
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
200
199
|
)
|
|
201
200
|
result = InferenceSimulatorModelListForProjectResponse.model_validate(response) if response else None
|
|
202
201
|
return result.inferenceSimulatorModels if result and result.is_success else None
|
|
203
202
|
|
|
204
203
|
def get_rented_instance_list(
|
|
205
204
|
self,
|
|
206
|
-
token: str,
|
|
207
205
|
statuses: List[str],
|
|
208
206
|
query: Optional[str] = None,
|
|
209
207
|
page: int = 1,
|
|
@@ -227,30 +225,30 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
227
225
|
method='POST',
|
|
228
226
|
url='/user-api/v2/instance-rented/list',
|
|
229
227
|
data=data,
|
|
230
|
-
token=
|
|
228
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
231
229
|
)
|
|
232
230
|
|
|
233
231
|
result = InstanceRentedListResponse.model_validate(response) if response else None
|
|
234
232
|
return result.paginated_list if result and result.paginated_list else ([], None)
|
|
235
233
|
|
|
236
|
-
def get_rented_business_status_map(self
|
|
234
|
+
def get_rented_business_status_map(self) -> Optional[Dict[str, str]]:
|
|
237
235
|
response = self._request(
|
|
238
236
|
method='POST',
|
|
239
237
|
url='/user-api/v2/instance-rented/business-status-localized-map',
|
|
240
238
|
data=None,
|
|
241
|
-
token=
|
|
239
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
242
240
|
)
|
|
243
241
|
|
|
244
242
|
data = InstanceRentedBusinessStatusMapperResponse.model_validate(response) if response else None
|
|
245
243
|
|
|
246
244
|
return data.instance_rented_business_status_map if data else None
|
|
247
245
|
|
|
248
|
-
def get_task_localized_status_map(self
|
|
246
|
+
def get_task_localized_status_map(self) -> Optional[Dict[str, str]]:
|
|
249
247
|
response = self._request(
|
|
250
248
|
method='POST',
|
|
251
249
|
url='/user-api/v1/task/status-localized-mapping',
|
|
252
250
|
data=None,
|
|
253
|
-
token=
|
|
251
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
254
252
|
)
|
|
255
253
|
|
|
256
254
|
data = TaskStatusLocalizedMapResponse.model_validate(response) if response else None
|
|
@@ -259,7 +257,6 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
259
257
|
|
|
260
258
|
def get_rented_instance(
|
|
261
259
|
self,
|
|
262
|
-
token: str,
|
|
263
260
|
instance_slug: Optional[str] = None,
|
|
264
261
|
instance_id: Optional[int] = None,
|
|
265
262
|
) -> Optional[InstanceRentedDto]:
|
|
@@ -274,14 +271,13 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
274
271
|
method='POST',
|
|
275
272
|
url='/user-api/v2/instance-rented/view-by-slug',
|
|
276
273
|
data=data,
|
|
277
|
-
token=
|
|
274
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
278
275
|
)
|
|
279
276
|
|
|
280
277
|
return InstanceRentedItemResponse.model_validate(response).instance_rented if response else None
|
|
281
278
|
|
|
282
279
|
def get_selfhosted_instance(
|
|
283
280
|
self,
|
|
284
|
-
token: str,
|
|
285
281
|
instance_slug: Optional[str] = None,
|
|
286
282
|
instance_id: Optional[int] = None,
|
|
287
283
|
) -> Optional[SelfHostedInstanceDto]:
|
|
@@ -296,14 +292,13 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
296
292
|
method='POST',
|
|
297
293
|
url='/user-api/v2/self-hosted-instance/view-by-slug',
|
|
298
294
|
data=data,
|
|
299
|
-
token=
|
|
295
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
300
296
|
)
|
|
301
297
|
|
|
302
298
|
return SelfHostedRentedItemResponse.model_validate(response).selfhosted_instance if response else None
|
|
303
299
|
|
|
304
300
|
def get_selfhosted_instance_list(
|
|
305
301
|
self,
|
|
306
|
-
token: str,
|
|
307
302
|
statuses: List[str],
|
|
308
303
|
query: Optional[str] = None,
|
|
309
304
|
page: int = 1,
|
|
@@ -327,18 +322,18 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
327
322
|
method='POST',
|
|
328
323
|
url='/user-api/v2/self-hosted-instance/list',
|
|
329
324
|
data=data,
|
|
330
|
-
token=
|
|
325
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
331
326
|
)
|
|
332
327
|
|
|
333
328
|
result = SelfHostedInstanceListResponse.model_validate(response) if response else None
|
|
334
329
|
return result.paginated_list if result and result.paginated_list else ([], None)
|
|
335
330
|
|
|
336
|
-
def get_selfhosted_business_status_map(self
|
|
331
|
+
def get_selfhosted_business_status_map(self) -> Optional[Dict[str, str]]:
|
|
337
332
|
response = self._request(
|
|
338
333
|
method='POST',
|
|
339
334
|
url='/user-api/v2/self-hosted-instance/business-status-localized-map',
|
|
340
335
|
data=None,
|
|
341
|
-
token=
|
|
336
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
342
337
|
)
|
|
343
338
|
|
|
344
339
|
data = SelfHostedRentedRentedBusinessStatusMapperResponse.model_validate(response) if response else None
|
|
@@ -347,7 +342,6 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
347
342
|
|
|
348
343
|
def cancel_task(
|
|
349
344
|
self,
|
|
350
|
-
token: str,
|
|
351
345
|
task_id: int,
|
|
352
346
|
) -> Optional[TheStageBaseResponse]:
|
|
353
347
|
data = {
|
|
@@ -358,7 +352,7 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
358
352
|
method='POST',
|
|
359
353
|
url='/user-api/v1/task/cancel-task',
|
|
360
354
|
data=data,
|
|
361
|
-
token=
|
|
355
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
362
356
|
)
|
|
363
357
|
|
|
364
358
|
result = TheStageBaseResponse.model_validate(response) if response else None
|
|
@@ -366,7 +360,6 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
366
360
|
|
|
367
361
|
def get_container_list(
|
|
368
362
|
self,
|
|
369
|
-
token: str,
|
|
370
363
|
project_id: Optional[int] = None,
|
|
371
364
|
statuses: List[str] = [],
|
|
372
365
|
page: int = 1,
|
|
@@ -387,7 +380,7 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
387
380
|
method='POST',
|
|
388
381
|
url='/user-api/v1/docker-container/list',
|
|
389
382
|
data=request.model_dump(),
|
|
390
|
-
token=
|
|
383
|
+
token=self.__config_provider.get_config().main.thestage_auth_token
|
|
391
384
|
)
|
|
392
385
|
|
|
393
386
|
result = DockerContainerListResponse.model_validate(response) if response else None
|
|
@@ -396,7 +389,6 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
396
389
|
|
|
397
390
|
def get_container(
|
|
398
391
|
self,
|
|
399
|
-
token: str,
|
|
400
392
|
container_slug: Optional[str] = None,
|
|
401
393
|
container_id: Optional[int] = None,
|
|
402
394
|
) -> Optional[DockerContainerDto]:
|
|
@@ -416,14 +408,13 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
416
408
|
method='POST',
|
|
417
409
|
url='/user-api/v1/docker-container/view',
|
|
418
410
|
data=data,
|
|
419
|
-
token=
|
|
411
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
420
412
|
)
|
|
421
413
|
|
|
422
414
|
return DockerContainerViewResponse.model_validate(response).docker_container if response else None
|
|
423
415
|
|
|
424
416
|
def container_action(
|
|
425
417
|
self,
|
|
426
|
-
token: str,
|
|
427
418
|
request_param: DockerContainerActionRequestDto,
|
|
428
419
|
) -> TheStageBaseResponse:
|
|
429
420
|
|
|
@@ -431,24 +422,24 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
431
422
|
method='POST',
|
|
432
423
|
url='/user-api/v1/docker-container/action',
|
|
433
424
|
data=request_param.model_dump(by_alias=True),
|
|
434
|
-
token=
|
|
425
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
435
426
|
)
|
|
436
427
|
|
|
437
428
|
result = TheStageBaseResponse.model_validate(response) if response else None
|
|
438
429
|
return result
|
|
439
430
|
|
|
440
|
-
def get_container_business_status_map(self
|
|
431
|
+
def get_container_business_status_map(self) -> Optional[Dict[str, str]]:
|
|
441
432
|
response = self._request(
|
|
442
433
|
method='POST',
|
|
443
434
|
url='/user-api/v1/docker-container/status-localized-mapping',
|
|
444
435
|
data=None,
|
|
445
|
-
token=
|
|
436
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
446
437
|
)
|
|
447
438
|
|
|
448
439
|
data = ContainerBusinessStatusMapperResponse.model_validate(response) if response else None
|
|
449
440
|
return data.docker_container_status_map if data else None
|
|
450
441
|
|
|
451
|
-
def get_project_by_slug(self, slug: str
|
|
442
|
+
def get_project_by_slug(self, slug: str) -> Optional[ProjectDto]:
|
|
452
443
|
data = {
|
|
453
444
|
"projectSlug": slug,
|
|
454
445
|
}
|
|
@@ -457,14 +448,14 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
457
448
|
method='POST',
|
|
458
449
|
url='/user-api/v1/project/view-by-slug',
|
|
459
450
|
data=data,
|
|
460
|
-
token=
|
|
451
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
461
452
|
)
|
|
462
453
|
|
|
463
454
|
result = ProjectViewResponse.model_validate(response) if response else None
|
|
464
455
|
project = ProjectDto.model_validate(result.project) if result else None
|
|
465
456
|
return project if result and result.is_success else None
|
|
466
457
|
|
|
467
|
-
def get_project_deploy_ssh_key(self, slug: str
|
|
458
|
+
def get_project_deploy_ssh_key(self, slug: str) -> str:
|
|
468
459
|
request = ProjectGetDeploySshKeyRequest(
|
|
469
460
|
projectSlug=slug
|
|
470
461
|
)
|
|
@@ -473,7 +464,7 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
473
464
|
method='POST',
|
|
474
465
|
url='/user-api/v1/project/get-deploy-ssh-key',
|
|
475
466
|
data=request.model_dump(),
|
|
476
|
-
token=
|
|
467
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
477
468
|
)
|
|
478
469
|
|
|
479
470
|
result = ProjectGetDeploySshKeyResponse.model_validate(response) if response else None
|
|
@@ -481,7 +472,6 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
481
472
|
|
|
482
473
|
def execute_project_task(
|
|
483
474
|
self,
|
|
484
|
-
token: str,
|
|
485
475
|
project_slug: str,
|
|
486
476
|
run_command: str,
|
|
487
477
|
task_title: str,
|
|
@@ -500,15 +490,16 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
500
490
|
method='POST',
|
|
501
491
|
url='/user-api/v1/project/execute-task',
|
|
502
492
|
data=request.model_dump(),
|
|
503
|
-
token=
|
|
493
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
504
494
|
)
|
|
505
495
|
|
|
506
496
|
return ProjectRunTaskResponse.model_validate(response) if response else None
|
|
507
497
|
|
|
508
|
-
async def poll_logs_httpx(self,
|
|
498
|
+
async def poll_logs_httpx(self, docker_container_id: Optional[int], last_log_timestamp: str,
|
|
509
499
|
last_log_id: str, task_id: Optional[int] = None,
|
|
510
500
|
inference_simulator_id: Optional[int] = None) -> Optional[LogPollingResponse]:
|
|
511
501
|
request_headers = {'Content-Type': 'application/json'}
|
|
502
|
+
token = self.__config_provider.get_config().main.thestage_auth_token
|
|
512
503
|
if token: request_headers['Authorization'] = f"Bearer {token}"
|
|
513
504
|
|
|
514
505
|
request = LogPollingRequest(
|
|
@@ -529,7 +520,7 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
529
520
|
|
|
530
521
|
return LogPollingResponse.model_validate(response.json()) if response else None
|
|
531
522
|
|
|
532
|
-
def add_public_ssh_key_to_user(self,
|
|
523
|
+
def add_public_ssh_key_to_user(self, public_key: str, note: str) -> AddSshKeyToUserResponse:
|
|
533
524
|
request = AddSshKeyToUserRequest(
|
|
534
525
|
sshKey=public_key,
|
|
535
526
|
note=note
|
|
@@ -539,13 +530,13 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
539
530
|
method='POST',
|
|
540
531
|
url='/user-api/v1/ssh-key/add-public-key-to-user',
|
|
541
532
|
data=request.model_dump(),
|
|
542
|
-
token=
|
|
533
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
543
534
|
)
|
|
544
535
|
|
|
545
536
|
result = AddSshKeyToUserResponse.model_validate(response) if response else None
|
|
546
537
|
return result
|
|
547
538
|
|
|
548
|
-
def is_user_has_ssh_public_key(self,
|
|
539
|
+
def is_user_has_ssh_public_key(self, public_key: str) -> IsUserHasSshPublicKeyResponse:
|
|
549
540
|
request = IsUserHasSshPublicKeyRequest(
|
|
550
541
|
sshKey=public_key,
|
|
551
542
|
)
|
|
@@ -554,13 +545,13 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
554
545
|
method='POST',
|
|
555
546
|
url='/user-api/v1/ssh-key/is-user-has-public-ssh-key',
|
|
556
547
|
data=request.model_dump(),
|
|
557
|
-
token=
|
|
548
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
558
549
|
)
|
|
559
550
|
|
|
560
551
|
result = IsUserHasSshPublicKeyResponse.model_validate(response) if response else None
|
|
561
552
|
return result
|
|
562
553
|
|
|
563
|
-
def add_public_ssh_key_to_instance_rented(self,
|
|
554
|
+
def add_public_ssh_key_to_instance_rented(self, instance_rented_id: int,
|
|
564
555
|
ssh_key_pair_id: int) -> AddSshPublicKeyToInstanceResponse:
|
|
565
556
|
request = AddSshPublicKeyToInstanceRequest(
|
|
566
557
|
instanceRentedId=instance_rented_id,
|
|
@@ -571,7 +562,7 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
571
562
|
method='POST',
|
|
572
563
|
url='/user-api/v1/ssh-key/add-public-ssh-key-to-instance-rented',
|
|
573
564
|
data=request.model_dump(),
|
|
574
|
-
token=
|
|
565
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
575
566
|
)
|
|
576
567
|
|
|
577
568
|
result = AddSshPublicKeyToInstanceResponse.model_validate(response) if response else None
|
|
@@ -579,7 +570,6 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
579
570
|
|
|
580
571
|
def start_project_inference_simulator(
|
|
581
572
|
self,
|
|
582
|
-
token: str,
|
|
583
573
|
project_slug: str,
|
|
584
574
|
slug: str,
|
|
585
575
|
commit_hash: Optional[str] = None,
|
|
@@ -602,14 +592,13 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
602
592
|
method='POST',
|
|
603
593
|
url='/user-api/v1/project/inference-simulator/create',
|
|
604
594
|
data=request.model_dump(),
|
|
605
|
-
token=
|
|
595
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
606
596
|
)
|
|
607
597
|
|
|
608
598
|
return ProjectStartInferenceSimulatorResponse.model_validate(response) if response else None
|
|
609
599
|
|
|
610
600
|
def push_project_inference_simulator_model(
|
|
611
601
|
self,
|
|
612
|
-
token: str,
|
|
613
602
|
slug: str,
|
|
614
603
|
) -> Optional[ProjectPushInferenceSimulatorModelResponse]:
|
|
615
604
|
request = ProjectPushInferenceSimulatorModelRequest(
|
|
@@ -620,29 +609,29 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
620
609
|
method='POST',
|
|
621
610
|
url='/user-api/v1/project/inference-simulator/push-model',
|
|
622
611
|
data=request.model_dump(),
|
|
623
|
-
token=
|
|
612
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
624
613
|
)
|
|
625
614
|
|
|
626
615
|
return ProjectPushInferenceSimulatorModelResponse.model_validate(response) if response else None
|
|
627
616
|
|
|
628
|
-
def get_inference_simulator_business_status_map(self
|
|
617
|
+
def get_inference_simulator_business_status_map(self) -> Optional[Dict[str, str]]:
|
|
629
618
|
response = self._request(
|
|
630
619
|
method='POST',
|
|
631
620
|
url='/user-api/v1/inference-simulator/status-localized-mapping',
|
|
632
621
|
data=None,
|
|
633
|
-
token=
|
|
622
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
634
623
|
)
|
|
635
624
|
|
|
636
625
|
data = InferenceSimulatorStatusMapperResponse.model_validate(response) if response else None
|
|
637
626
|
|
|
638
627
|
return data.inference_simulator_status_map if data else None
|
|
639
628
|
|
|
640
|
-
def get_inference_simulator_model_business_status_map(self
|
|
629
|
+
def get_inference_simulator_model_business_status_map(self) -> Optional[Dict[str, str]]:
|
|
641
630
|
response = self._request(
|
|
642
631
|
method='POST',
|
|
643
632
|
url='/user-api/v1/inference-simulator-model/status-localized-mapping',
|
|
644
633
|
data=None,
|
|
645
|
-
token=
|
|
634
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
646
635
|
)
|
|
647
636
|
|
|
648
637
|
data = InferenceSimulatorModelStatusMapperResponse.model_validate(response) if response else None
|
|
@@ -652,7 +641,6 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
652
641
|
@error_handler()
|
|
653
642
|
def get_inference_simulator(
|
|
654
643
|
self,
|
|
655
|
-
token: str,
|
|
656
644
|
slug: str,
|
|
657
645
|
) -> Optional[GetInferenceSimulatorResponse]:
|
|
658
646
|
request = GetInferenceSimulatorRequest(
|
|
@@ -663,14 +651,13 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
663
651
|
method='POST',
|
|
664
652
|
url='/user-api/v1/inference-simulator/get',
|
|
665
653
|
data=request.model_dump(),
|
|
666
|
-
token=
|
|
654
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
667
655
|
)
|
|
668
656
|
return GetInferenceSimulatorResponse.model_validate(response) if response else None
|
|
669
657
|
|
|
670
658
|
@error_handler()
|
|
671
659
|
def deploy_inference_model_to_instance(
|
|
672
660
|
self,
|
|
673
|
-
token: str,
|
|
674
661
|
unique_id: str,
|
|
675
662
|
unique_id_with_timestamp: str,
|
|
676
663
|
rented_instance_unique_id: Optional[str] = None,
|
|
@@ -688,14 +675,13 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
688
675
|
method='POST',
|
|
689
676
|
url='/user-api/v1/inference-simulator-model/deploy/instance',
|
|
690
677
|
data=request.model_dump(),
|
|
691
|
-
token=
|
|
678
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
692
679
|
)
|
|
693
680
|
return DeployInferenceModelToInstanceResponse.model_validate(response) if response else None
|
|
694
681
|
|
|
695
682
|
@error_handler()
|
|
696
683
|
def deploy_inference_model_to_sagemaker(
|
|
697
684
|
self,
|
|
698
|
-
token: str,
|
|
699
685
|
unique_id: str,
|
|
700
686
|
arn: Optional[str] = None,
|
|
701
687
|
) -> Optional[DeployInferenceModelToSagemakerResponse]:
|
|
@@ -708,11 +694,11 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
708
694
|
method='POST',
|
|
709
695
|
url='/user-api/v1/inference-simulator-model/grant-user-arn-access',
|
|
710
696
|
data=request.model_dump(),
|
|
711
|
-
token=
|
|
697
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
712
698
|
)
|
|
713
699
|
return DeployInferenceModelToSagemakerResponse.model_validate(response) if response else None
|
|
714
700
|
|
|
715
|
-
def query_user_logs(self,
|
|
701
|
+
def query_user_logs(self, limit: int, task_id: Optional[int] = None,
|
|
716
702
|
inference_simulator_id: Optional[int] = None,
|
|
717
703
|
container_id: Optional[int] = None) -> UserLogsQueryResponse:
|
|
718
704
|
request = UserLogsQueryRequest(
|
|
@@ -727,7 +713,7 @@ class TheStageApiClient(TheStageApiClientCore):
|
|
|
727
713
|
method='POST',
|
|
728
714
|
url='/user-api/v1/logging/query-user-logs',
|
|
729
715
|
data=request.model_dump(),
|
|
730
|
-
token=
|
|
716
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
731
717
|
)
|
|
732
718
|
|
|
733
719
|
result = UserLogsQueryResponse.model_validate(response) if response else None
|
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
import json
|
|
2
|
+
from typing import Optional
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
import requests
|
|
5
|
+
|
|
6
|
+
from thestage.config import THESTAGE_API_URL
|
|
7
|
+
from thestage.exceptions.auth_exception import AuthException
|
|
5
8
|
from thestage import __version__
|
|
9
|
+
from thestage.services.clients.thestage_api.core.http_client_exception import HttpClientException
|
|
10
|
+
from thestage.services.clients.thestage_api.dtos.validate_token_response import ValidateTokenResponse
|
|
6
11
|
|
|
7
12
|
|
|
8
|
-
class TheStageApiClientCore
|
|
13
|
+
class TheStageApiClientCore:
|
|
14
|
+
def __init__(self, url: Optional[str] = None):
|
|
15
|
+
self.__api_url = url
|
|
9
16
|
|
|
10
|
-
def __init__(self, timeout: int = 90, url: Optional[str] = None):
|
|
11
|
-
super(TheStageApiClientCore, self).__init__(timeout=timeout, url=url)
|
|
12
17
|
|
|
13
|
-
def validate_token(self, token: str) ->
|
|
18
|
+
def validate_token(self, token: str) -> ValidateTokenResponse:
|
|
14
19
|
data = {
|
|
15
20
|
"userApiToken": token,
|
|
16
21
|
"cliVersion": __version__,
|
|
@@ -21,5 +26,83 @@ class TheStageApiClientCore(TheStageApiClientAbstract):
|
|
|
21
26
|
url='/user-api/v1/validate-token',
|
|
22
27
|
data=data,
|
|
23
28
|
)
|
|
24
|
-
result =
|
|
25
|
-
return result
|
|
29
|
+
result = ValidateTokenResponse.model_validate(response) if response else None
|
|
30
|
+
return result
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _get_host(self, ) -> str:
|
|
34
|
+
return self.__api_url or THESTAGE_API_URL
|
|
35
|
+
|
|
36
|
+
def _request(
|
|
37
|
+
self,
|
|
38
|
+
method: str,
|
|
39
|
+
url: str,
|
|
40
|
+
data: dict = None,
|
|
41
|
+
query_params: dict = None,
|
|
42
|
+
headers: Optional[dict] = None,
|
|
43
|
+
token: Optional[str] = None,
|
|
44
|
+
):
|
|
45
|
+
if not data:
|
|
46
|
+
data = {}
|
|
47
|
+
|
|
48
|
+
host = self._get_host()
|
|
49
|
+
url = f'{host}{url}'
|
|
50
|
+
|
|
51
|
+
request_headers = {
|
|
52
|
+
'Content-Type': 'application/json',
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if token:
|
|
56
|
+
request_headers['Authorization'] = f"Bearer {token}"
|
|
57
|
+
|
|
58
|
+
if headers:
|
|
59
|
+
request_headers.update(headers)
|
|
60
|
+
response = requests.request(
|
|
61
|
+
method=method,
|
|
62
|
+
url=url,
|
|
63
|
+
json=data,
|
|
64
|
+
params=query_params,
|
|
65
|
+
headers=request_headers,
|
|
66
|
+
timeout=90,
|
|
67
|
+
|
|
68
|
+
)
|
|
69
|
+
return self._parse_api_response(response)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@staticmethod
|
|
73
|
+
def _parse_api_response(raw_response):
|
|
74
|
+
content_type = raw_response.headers.get('content-type')
|
|
75
|
+
message_error = None
|
|
76
|
+
if content_type == 'application/json':
|
|
77
|
+
try:
|
|
78
|
+
result = raw_response.json()
|
|
79
|
+
message_error = result.get('message', None)
|
|
80
|
+
except json.JSONDecodeError:
|
|
81
|
+
raise HttpClientException(
|
|
82
|
+
message=f"Failed to parse server response",
|
|
83
|
+
status_code=raw_response.status_code,
|
|
84
|
+
)
|
|
85
|
+
else:
|
|
86
|
+
result = raw_response.content.text()
|
|
87
|
+
|
|
88
|
+
if raw_response.status_code == 401:
|
|
89
|
+
raise AuthException(
|
|
90
|
+
message=f"Unauthorized",
|
|
91
|
+
)
|
|
92
|
+
elif raw_response.status_code == 403:
|
|
93
|
+
raise HttpClientException(
|
|
94
|
+
message=f"{message_error if message_error else 'Forbidden'} ({raw_response.status_code})",
|
|
95
|
+
status_code=raw_response.status_code,
|
|
96
|
+
)
|
|
97
|
+
elif raw_response.status_code >= 400:
|
|
98
|
+
raise HttpClientException(
|
|
99
|
+
message=f"{message_error if message_error else 'Request error'} ({raw_response.status_code})",
|
|
100
|
+
status_code=raw_response.status_code,
|
|
101
|
+
)
|
|
102
|
+
elif raw_response.status_code < 200 or raw_response.status_code > 300:
|
|
103
|
+
raise HttpClientException(
|
|
104
|
+
message=f"{message_error if message_error else 'Request error'} ({raw_response.status_code})",
|
|
105
|
+
status_code=raw_response.status_code,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
return result
|
|
@@ -64,4 +64,4 @@ class DockerContainerViewResponse(TheStageBaseResponse):
|
|
|
64
64
|
class ContainerBusinessStatusMapperResponse(TheStageBasePaginatedResponse):
|
|
65
65
|
model_config = ConfigDict(use_enum_values=True)
|
|
66
66
|
|
|
67
|
-
docker_container_status_map: Dict[str, str] = Field(default=
|
|
67
|
+
docker_container_status_map: Dict[str, str] = Field(default={}, alias='dockerContainerStatusMap')
|
|
@@ -8,4 +8,4 @@ from thestage.services.clients.thestage_api.dtos.base_response import TheStageBa
|
|
|
8
8
|
class InferenceSimulatorModelStatusMapperResponse(TheStageBasePaginatedResponse):
|
|
9
9
|
model_config = ConfigDict(use_enum_values=True)
|
|
10
10
|
|
|
11
|
-
inference_simulator_model_status_map: Dict[str, str] = Field(default=
|
|
11
|
+
inference_simulator_model_status_map: Dict[str, str] = Field(default={}, alias='inferenceSimulatorModelStatusMap')
|
|
@@ -8,4 +8,4 @@ from thestage.services.clients.thestage_api.dtos.base_response import TheStageBa
|
|
|
8
8
|
class InferenceSimulatorStatusMapperResponse(TheStageBasePaginatedResponse):
|
|
9
9
|
model_config = ConfigDict(use_enum_values=True)
|
|
10
10
|
|
|
11
|
-
inference_simulator_status_map: Dict[str, str] = Field(default=
|
|
11
|
+
inference_simulator_status_map: Dict[str, str] = Field(default={}, alias='inferenceSimulatorStatusMap')
|
|
@@ -68,4 +68,4 @@ class InstanceRentedItemResponse(TheStageBasePaginatedResponse):
|
|
|
68
68
|
class InstanceRentedBusinessStatusMapperResponse(TheStageBasePaginatedResponse):
|
|
69
69
|
model_config = ConfigDict(use_enum_values=True)
|
|
70
70
|
|
|
71
|
-
instance_rented_business_status_map: Dict[str, str] = Field(default=
|
|
71
|
+
instance_rented_business_status_map: Dict[str, str] = Field(default={}, alias='instanceRentedBusinessStatusMap')
|
|
@@ -53,4 +53,4 @@ class SelfHostedRentedItemResponse(TheStageBasePaginatedResponse):
|
|
|
53
53
|
class SelfHostedRentedRentedBusinessStatusMapperResponse(TheStageBasePaginatedResponse):
|
|
54
54
|
model_config = ConfigDict(use_enum_values=True)
|
|
55
55
|
|
|
56
|
-
selfhosted_instance_business_status_map: Dict[str, str] = Field(default=
|
|
56
|
+
selfhosted_instance_business_status_map: Dict[str, str] = Field(default={}, alias='selfhostedInstanceBusinessStatusMap')
|
thestage/services/clients/thestage_api/dtos/task_controller/task_status_localized_map_response.py
CHANGED
|
@@ -6,4 +6,4 @@ from thestage.services.clients.thestage_api.dtos.base_response import TheStageBa
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class TaskStatusLocalizedMapResponse(TheStageBaseResponse):
|
|
9
|
-
taskStatusMap: Dict[str, str] = Field(default=
|
|
9
|
+
taskStatusMap: Dict[str, str] = Field(default={}, alias='taskStatusMap')
|