thestage 0.6.5__py3-none-any.whl → 0.6.7__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/__init__.py +1 -1
- thestage/color_scheme/color_scheme.py +1 -0
- thestage/controllers/base_controller.py +4 -3
- thestage/controllers/config_controller.py +16 -4
- thestage/controllers/container_controller.py +151 -106
- thestage/controllers/instance_controller.py +35 -9
- thestage/controllers/project_controller.py +335 -89
- thestage/entities/container.py +5 -3
- thestage/entities/project_inference_simulator.py +2 -1
- thestage/entities/project_inference_simulator_model.py +2 -2
- thestage/entities/project_task.py +2 -3
- thestage/entities/rented_instance.py +2 -2
- thestage/entities/self_hosted_instance.py +2 -2
- thestage/helpers/error_handler.py +1 -1
- thestage/main.py +1 -1
- thestage/services/clients/git/git_client.py +1 -1
- thestage/services/clients/thestage_api/api_client.py +142 -109
- thestage/services/clients/thestage_api/dtos/base_controller/connect_resolve_response.py +22 -0
- thestage/services/clients/thestage_api/dtos/container_param_request.py +1 -1
- thestage/services/clients/thestage_api/dtos/container_response.py +1 -21
- thestage/services/clients/thestage_api/dtos/docker_container_controller/docker_container_list_request.py +2 -1
- thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_instance_request.py +5 -1
- thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_instance_response.py +2 -1
- thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_sagemaker_request.py +1 -0
- thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_request.py +2 -1
- thestage/services/clients/thestage_api/dtos/inference_controller/{inference_simulator_list_for_project_request.py → inference_simulator_list_request.py} +3 -2
- thestage/services/clients/thestage_api/dtos/inference_controller/{inference_simulator_list_for_project_response.py → inference_simulator_list_response.py} +1 -1
- thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_model_list_for_project_request.py +2 -1
- thestage/services/clients/thestage_api/dtos/instance_rented_response.py +4 -37
- thestage/services/clients/thestage_api/dtos/logging_controller/log_polling_request.py +3 -3
- thestage/services/clients/thestage_api/dtos/logging_controller/user_logs_query_request.py +3 -11
- thestage/services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_request.py +1 -0
- thestage/services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_request.py +2 -1
- thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_request.py +2 -4
- thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_response.py +3 -0
- thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_request.py +5 -3
- thestage/services/clients/thestage_api/dtos/project_response.py +3 -15
- thestage/services/clients/thestage_api/dtos/selfhosted_instance_response.py +2 -20
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_key_to_user_response.py +1 -1
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_public_key_to_instance_request.py +4 -2
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/is_user_has_public_ssh_key_response.py +1 -1
- thestage/services/clients/thestage_api/dtos/task_controller/task_list_for_project_request.py +4 -1
- thestage/services/clients/thestage_api/dtos/task_controller/task_view_response.py +0 -2
- thestage/services/config_provider/config_provider.py +2 -2
- thestage/services/connect/connect_service.py +77 -74
- thestage/services/container/container_service.py +120 -41
- thestage/services/container/mapper/container_mapper.py +2 -1
- thestage/services/instance/instance_service.py +13 -20
- thestage/services/instance/mapper/instance_mapper.py +1 -3
- thestage/services/instance/mapper/selfhosted_mapper.py +3 -4
- thestage/services/logging/logging_service.py +45 -48
- thestage/services/project/dto/inference_simulator_dto.py +1 -10
- thestage/services/project/dto/inference_simulator_model_dto.py +2 -10
- thestage/services/project/dto/project_config.py +2 -2
- thestage/services/project/mapper/project_inference_simulator_mapper.py +1 -0
- thestage/services/project/mapper/project_inference_simulator_model_mapper.py +2 -2
- thestage/services/project/mapper/project_task_mapper.py +2 -3
- thestage/services/project/project_service.py +174 -140
- thestage/services/remote_server_service.py +1 -0
- thestage/services/task/dto/task_dto.py +3 -23
- {thestage-0.6.5.dist-info → thestage-0.6.7.dist-info}/METADATA +4 -2
- {thestage-0.6.5.dist-info → thestage-0.6.7.dist-info}/RECORD +65 -74
- {thestage-0.6.5.dist-info → thestage-0.6.7.dist-info}/WHEEL +1 -1
- thestage/services/clients/thestage_api/dtos/cloud_provider_region.py +0 -19
- thestage/services/clients/thestage_api/dtos/docker_container_assigned_device.py +0 -10
- thestage/services/clients/thestage_api/dtos/enums/currency_type.py +0 -10
- thestage/services/clients/thestage_api/dtos/enums/daemon_status.py +0 -9
- thestage/services/clients/thestage_api/dtos/enums/disk_type.py +0 -7
- thestage/services/clients/thestage_api/dtos/enums/drive_type.py +0 -7
- thestage/services/clients/thestage_api/dtos/enums/instance_type.py +0 -7
- thestage/services/clients/thestage_api/dtos/enums/location_region.py +0 -11
- thestage/services/clients/thestage_api/dtos/enums/power_status.py +0 -10
- thestage/services/clients/thestage_api/dtos/price_definition.py +0 -14
- {thestage-0.6.5.dist-info → thestage-0.6.7.dist-info}/entry_points.txt +0 -0
- {thestage-0.6.5.dist-info → thestage-0.6.7.dist-info/licenses}/LICENSE.txt +0 -0
|
@@ -80,11 +80,13 @@ class ProjectService(AbstractService):
|
|
|
80
80
|
@error_handler()
|
|
81
81
|
def init_project(
|
|
82
82
|
self,
|
|
83
|
-
project_slug: str,
|
|
83
|
+
project_slug: Optional[str] = None,
|
|
84
|
+
project_public_id: Optional[str] = None,
|
|
84
85
|
):
|
|
85
86
|
config = self.__config_provider.get_config()
|
|
86
|
-
project: Optional[ProjectDto] = self.__thestage_api_client.
|
|
87
|
+
project: Optional[ProjectDto] = self.__thestage_api_client.get_project(
|
|
87
88
|
slug=project_slug,
|
|
89
|
+
public_id=project_public_id,
|
|
88
90
|
)
|
|
89
91
|
|
|
90
92
|
if not project:
|
|
@@ -119,13 +121,12 @@ class ProjectService(AbstractService):
|
|
|
119
121
|
raise typer.Exit(0)
|
|
120
122
|
|
|
121
123
|
deploy_ssh_key = self.__thestage_api_client.get_project_deploy_ssh_key(
|
|
122
|
-
|
|
124
|
+
public_id=project.public_id,
|
|
123
125
|
)
|
|
124
126
|
|
|
125
127
|
deploy_key_path = self.__config_provider.save_project_deploy_ssh_key(
|
|
126
128
|
deploy_ssh_key=deploy_ssh_key,
|
|
127
|
-
|
|
128
|
-
project_id=project.id,
|
|
129
|
+
project_public_id=project.public_id,
|
|
129
130
|
)
|
|
130
131
|
|
|
131
132
|
if is_git_folder:
|
|
@@ -156,7 +157,7 @@ class ProjectService(AbstractService):
|
|
|
156
157
|
self.__git_local_client.git_add_all(repo_path=config.runtime.working_directory)
|
|
157
158
|
|
|
158
159
|
project_config = ProjectConfig()
|
|
159
|
-
project_config.
|
|
160
|
+
project_config.public_id = project.public_id
|
|
160
161
|
project_config.slug = project.slug
|
|
161
162
|
project_config.git_repository_url = project.git_repository_url
|
|
162
163
|
project_config.deploy_key_path = str(deploy_key_path)
|
|
@@ -169,10 +170,12 @@ class ProjectService(AbstractService):
|
|
|
169
170
|
def clone_project(
|
|
170
171
|
self,
|
|
171
172
|
project_slug: str,
|
|
173
|
+
project_public_id: str
|
|
172
174
|
):
|
|
173
175
|
config = self.__config_provider.get_config()
|
|
174
|
-
project: Optional[ProjectDto] = self.__thestage_api_client.
|
|
176
|
+
project: Optional[ProjectDto] = self.__thestage_api_client.get_project(
|
|
175
177
|
slug=project_slug,
|
|
178
|
+
public_id=project_public_id
|
|
176
179
|
)
|
|
177
180
|
|
|
178
181
|
if not project:
|
|
@@ -195,8 +198,8 @@ class ProjectService(AbstractService):
|
|
|
195
198
|
typer.echo(__("Unexpected Project error, missing Repository"))
|
|
196
199
|
raise typer.Exit(1)
|
|
197
200
|
|
|
198
|
-
deploy_ssh_key = self.__thestage_api_client.get_project_deploy_ssh_key(
|
|
199
|
-
deploy_key_path = self.__config_provider.save_project_deploy_ssh_key(deploy_ssh_key=deploy_ssh_key,
|
|
201
|
+
deploy_ssh_key = self.__thestage_api_client.get_project_deploy_ssh_key(public_id=project.public_id)
|
|
202
|
+
deploy_key_path = self.__config_provider.save_project_deploy_ssh_key(deploy_ssh_key=deploy_ssh_key, project_public_id=project.public_id,)
|
|
200
203
|
|
|
201
204
|
try:
|
|
202
205
|
self.__git_local_client.clone(
|
|
@@ -217,7 +220,7 @@ class ProjectService(AbstractService):
|
|
|
217
220
|
raise typer.Exit(1)
|
|
218
221
|
|
|
219
222
|
project_config = ProjectConfig()
|
|
220
|
-
project_config.
|
|
223
|
+
project_config.public_id = project.public_id
|
|
221
224
|
project_config.slug = project.slug
|
|
222
225
|
project_config.git_repository_url = project.git_repository_url
|
|
223
226
|
project_config.deploy_key_path = str(deploy_key_path)
|
|
@@ -229,9 +232,10 @@ class ProjectService(AbstractService):
|
|
|
229
232
|
def project_run_task(
|
|
230
233
|
self,
|
|
231
234
|
run_command: str,
|
|
235
|
+
docker_container_slug: str,
|
|
236
|
+
docker_container_public_id: str,
|
|
232
237
|
task_title: Optional[str] = None,
|
|
233
238
|
commit_hash: Optional[str] = None,
|
|
234
|
-
docker_container_slug: Optional[str] = None,
|
|
235
239
|
files_to_add: Optional[str] = None,
|
|
236
240
|
is_skip_auto_commit: Optional[bool] = False,
|
|
237
241
|
) -> Optional[TaskDto]:
|
|
@@ -241,43 +245,48 @@ class ProjectService(AbstractService):
|
|
|
241
245
|
typer.echo(__("No project found at the path: %path%. Please initialize or clone a project first.", {"path": config.runtime.working_directory}))
|
|
242
246
|
raise typer.Exit(1)
|
|
243
247
|
|
|
244
|
-
if not docker_container_slug and not project_config.
|
|
245
|
-
typer.echo(__('Docker container
|
|
248
|
+
if not docker_container_public_id and not docker_container_slug and not project_config.default_container_public_id:
|
|
249
|
+
typer.echo(__('Docker container ID or name is required'))
|
|
246
250
|
raise typer.Exit(1)
|
|
247
251
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if not
|
|
251
|
-
|
|
252
|
+
final_container_public_id = docker_container_public_id
|
|
253
|
+
final_container_slug = docker_container_slug
|
|
254
|
+
if not final_container_public_id and not final_container_slug:
|
|
255
|
+
final_container_public_id = project_config.default_container_public_id
|
|
256
|
+
typer.echo(f"Using default docker container for this project: '{project_config.default_container_public_id}'")
|
|
252
257
|
|
|
253
258
|
container: DockerContainerDto = self.__thestage_api_client.get_container(
|
|
254
|
-
container_slug=
|
|
259
|
+
container_slug=final_container_slug,
|
|
260
|
+
container_public_id=final_container_public_id
|
|
255
261
|
)
|
|
256
262
|
|
|
257
263
|
if container is None:
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
264
|
+
if final_container_slug:
|
|
265
|
+
typer.echo(f"Could not find container with name '{final_container_slug}'")
|
|
266
|
+
if final_container_public_id:
|
|
267
|
+
typer.echo(f"Could not find container with ID '{final_container_public_id}'")
|
|
268
|
+
if project_config.default_container_public_id == final_container_public_id:
|
|
269
|
+
project_config.default_container_public_id = None
|
|
261
270
|
project_config.prompt_for_default_container = True
|
|
262
271
|
self.__config_provider.save_project_config(project_config=project_config)
|
|
263
272
|
typer.echo(f"Default container settings were reset")
|
|
264
273
|
raise typer.Exit(1)
|
|
265
274
|
|
|
266
|
-
if container.
|
|
267
|
-
typer.echo(f"Provided container '{
|
|
275
|
+
if container.project.public_id != project_config.public_id:
|
|
276
|
+
typer.echo(f"Provided container '{container.public_id}' is not related to project '{project_config.public_id}'")
|
|
268
277
|
raise typer.Exit(1)
|
|
269
278
|
|
|
270
|
-
if (project_config.prompt_for_default_container is None or project_config.prompt_for_default_container) and docker_container_slug and (project_config.
|
|
271
|
-
|
|
272
|
-
text=f"Would you like to set '{
|
|
279
|
+
if (project_config.prompt_for_default_container is None or project_config.prompt_for_default_container) and (docker_container_slug or docker_container_public_id) and (project_config.default_container_public_id != container.public_id):
|
|
280
|
+
set_default_container_answer: str = typer.prompt(
|
|
281
|
+
text=f"Would you like to set the container '{container.slug}' (ID: '{container.public_id}') as default for this project installation?",
|
|
273
282
|
show_choices=True,
|
|
274
283
|
default=YesOrNoResponse.YES.value,
|
|
275
284
|
type=click.Choice([r.value for r in YesOrNoResponse]),
|
|
276
285
|
show_default=True,
|
|
277
286
|
)
|
|
278
287
|
project_config.prompt_for_default_container = False
|
|
279
|
-
if
|
|
280
|
-
project_config.
|
|
288
|
+
if set_default_container_answer == YesOrNoResponse.YES.value:
|
|
289
|
+
project_config.default_container_public_id = container.public_id
|
|
281
290
|
|
|
282
291
|
self.__config_provider.save_project_config(project_config=project_config)
|
|
283
292
|
|
|
@@ -395,8 +404,8 @@ class ProjectService(AbstractService):
|
|
|
395
404
|
typer.echo(f'Commit message is empty. Task title is set to "{task_title}"')
|
|
396
405
|
|
|
397
406
|
run_task_response: ProjectRunTaskResponse = self.__thestage_api_client.execute_project_task(
|
|
398
|
-
|
|
399
|
-
|
|
407
|
+
project_public_id=project_config.public_id,
|
|
408
|
+
docker_container_public_id=container.public_id,
|
|
400
409
|
run_command=run_command,
|
|
401
410
|
commit_hash=commit_hash,
|
|
402
411
|
task_title=task_title,
|
|
@@ -405,7 +414,11 @@ class ProjectService(AbstractService):
|
|
|
405
414
|
if run_task_response.message:
|
|
406
415
|
print(f"[{ColorScheme.WARNING.value}]{run_task_response.message}[{ColorScheme.WARNING.value}]")
|
|
407
416
|
if run_task_response.is_success and run_task_response.task:
|
|
408
|
-
typer.echo(f"Task '{run_task_response.task.title}' has been scheduled successfully. Task ID: {run_task_response.task.
|
|
417
|
+
typer.echo(f"Task '{run_task_response.task.title}' has been scheduled successfully. Task ID: {run_task_response.task.public_id}")
|
|
418
|
+
if run_task_response.tasksInQueue:
|
|
419
|
+
typer.echo(f"There are tasks in queue ahead of this new task:")
|
|
420
|
+
for queued_task_item in run_task_response.tasksInQueue:
|
|
421
|
+
typer.echo(f"{queued_task_item.public_id} - {queued_task_item.frontend_status.status_translation}")
|
|
409
422
|
return run_task_response.task
|
|
410
423
|
else:
|
|
411
424
|
typer.echo(f'The task failed with an error: {run_task_response.message}')
|
|
@@ -415,23 +428,25 @@ class ProjectService(AbstractService):
|
|
|
415
428
|
raise typer.Exit(1)
|
|
416
429
|
|
|
417
430
|
@error_handler()
|
|
418
|
-
def cancel_task(self,
|
|
431
|
+
def cancel_task(self, task_public_id: str):
|
|
419
432
|
cancel_result = self.__thestage_api_client.cancel_task(
|
|
420
|
-
|
|
433
|
+
task_public_id=task_public_id,
|
|
421
434
|
)
|
|
422
435
|
|
|
423
436
|
if cancel_result.is_success:
|
|
424
|
-
typer.echo(f'Task {
|
|
437
|
+
typer.echo(f'Task {task_public_id} has been canceled')
|
|
425
438
|
else:
|
|
426
|
-
typer.echo(f'Task {
|
|
439
|
+
typer.echo(f'Task {task_public_id} could not be canceled: {cancel_result.message}')
|
|
427
440
|
|
|
428
441
|
|
|
429
442
|
@error_handler()
|
|
430
443
|
def project_run_inference_simulator(
|
|
431
444
|
self,
|
|
432
445
|
commit_hash: Optional[str] = None,
|
|
433
|
-
|
|
434
|
-
|
|
446
|
+
rented_instance_public_id: Optional[str] = None,
|
|
447
|
+
rented_instance_slug: Optional[str] = None,
|
|
448
|
+
self_hosted_instance_public_id: Optional[str] = None,
|
|
449
|
+
self_hosted_instance_slug: Optional[str] = None,
|
|
435
450
|
inference_dir: Optional[str] = None,
|
|
436
451
|
is_skip_installation: Optional[bool] = False,
|
|
437
452
|
files_to_add: Optional[str] = None,
|
|
@@ -444,16 +459,12 @@ class ProjectService(AbstractService):
|
|
|
444
459
|
{"path": config.runtime.working_directory}))
|
|
445
460
|
raise typer.Exit(1)
|
|
446
461
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
if not rented_instance_unique_id and not self_hosted_instance_unique_id:
|
|
452
|
-
typer.echo(__("Error: Either a rented instance ID or a self-hosted instance unique ID must be provided."))
|
|
462
|
+
instance_args_count = sum(v is not None for v in [rented_instance_public_id, rented_instance_slug, self_hosted_instance_public_id, self_hosted_instance_slug])
|
|
463
|
+
if instance_args_count != 1:
|
|
464
|
+
typer.echo("Please provide a single instance (rented or self-hosted) identifier - name or ID.")
|
|
453
465
|
raise typer.Exit(1)
|
|
454
466
|
|
|
455
467
|
has_wrong_args = files_to_add and commit_hash or is_skip_auto_commit and commit_hash or files_to_add and is_skip_auto_commit
|
|
456
|
-
|
|
457
468
|
if has_wrong_args:
|
|
458
469
|
warning_msg = f"[{ColorScheme.WARNING.value}][WARNING] You can provide only one of the following arguments: --commit-hash, --files-add, --skip-autocommit[{ColorScheme.WARNING.value}]"
|
|
459
470
|
print(warning_msg)
|
|
@@ -555,10 +566,12 @@ class ProjectService(AbstractService):
|
|
|
555
566
|
commit_hash = commit.hexsha
|
|
556
567
|
|
|
557
568
|
start_inference_simulator_response: ProjectStartInferenceSimulatorResponse = self.__thestage_api_client.start_project_inference_simulator(
|
|
558
|
-
|
|
569
|
+
project_public_id=project_config.public_id,
|
|
559
570
|
commit_hash=commit_hash,
|
|
560
|
-
|
|
561
|
-
|
|
571
|
+
rented_instance_public_id=rented_instance_public_id,
|
|
572
|
+
rented_instance_slug=rented_instance_slug,
|
|
573
|
+
self_hosted_instance_public_id=self_hosted_instance_public_id,
|
|
574
|
+
self_hosted_instance_slug=self_hosted_instance_slug,
|
|
562
575
|
inference_dir=inference_dir,
|
|
563
576
|
is_skip_installation=is_skip_installation,
|
|
564
577
|
)
|
|
@@ -582,10 +595,12 @@ class ProjectService(AbstractService):
|
|
|
582
595
|
@error_handler()
|
|
583
596
|
def project_push_inference_simulator(
|
|
584
597
|
self,
|
|
598
|
+
public_id: Optional[str] = None,
|
|
585
599
|
slug: Optional[str] = None,
|
|
586
600
|
):
|
|
587
601
|
|
|
588
602
|
push_inference_simulator_model_response: ProjectPushInferenceSimulatorModelResponse = self.__thestage_api_client.push_project_inference_simulator_model(
|
|
603
|
+
public_id=public_id,
|
|
589
604
|
slug=slug,
|
|
590
605
|
)
|
|
591
606
|
if push_inference_simulator_model_response:
|
|
@@ -606,25 +621,27 @@ class ProjectService(AbstractService):
|
|
|
606
621
|
@error_handler()
|
|
607
622
|
def project_get_and_save_inference_simulator_metadata(
|
|
608
623
|
self,
|
|
609
|
-
|
|
624
|
+
inference_simulator_public_id: Optional[str] = None,
|
|
625
|
+
inference_simulator_slug: Optional[str] = None,
|
|
610
626
|
file_path: Optional[str] = None,
|
|
611
627
|
):
|
|
612
628
|
get_inference_metadata_response: GetInferenceSimulatorResponse = self.__thestage_api_client.get_inference_simulator(
|
|
613
|
-
|
|
629
|
+
public_id=inference_simulator_public_id,
|
|
630
|
+
slug=inference_simulator_slug,
|
|
614
631
|
)
|
|
615
632
|
|
|
616
633
|
metadata = get_inference_metadata_response.inferenceSimulator.qlip_serve_metadata
|
|
617
634
|
|
|
618
635
|
if metadata:
|
|
619
636
|
typer.echo("qlip_serve_metadata:")
|
|
620
|
-
typer.echo(json.dumps(
|
|
637
|
+
typer.echo(json.dumps(metadata, indent=4))
|
|
621
638
|
|
|
622
639
|
if not file_path:
|
|
623
640
|
file_path = Path(os.getcwd()) / "metadata.json"
|
|
624
641
|
typer.echo(__("No file path provided. Saving metadata to %file_path%", {"file_path": str(file_path)}))
|
|
625
642
|
|
|
626
643
|
try:
|
|
627
|
-
parsed_metadata =
|
|
644
|
+
parsed_metadata = metadata
|
|
628
645
|
|
|
629
646
|
output_file = Path(file_path)
|
|
630
647
|
output_file.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -643,13 +660,15 @@ class ProjectService(AbstractService):
|
|
|
643
660
|
@error_handler()
|
|
644
661
|
def get_project_inference_simulator_list(
|
|
645
662
|
self,
|
|
646
|
-
|
|
663
|
+
project_public_id: Optional[str],
|
|
664
|
+
project_slug: Optional[str],
|
|
647
665
|
statuses: List[str],
|
|
648
666
|
row: int = 5,
|
|
649
667
|
page: int = 1,
|
|
650
668
|
) -> PaginatedEntityList[InferenceSimulatorDto]:
|
|
651
|
-
data: Optional[PaginatedEntityList[InferenceSimulatorDto]] = self.__thestage_api_client.
|
|
669
|
+
data: Optional[PaginatedEntityList[InferenceSimulatorDto]] = self.__thestage_api_client.get_inference_simulator_list(
|
|
652
670
|
statuses=statuses,
|
|
671
|
+
project_public_id=project_public_id,
|
|
653
672
|
project_slug=project_slug,
|
|
654
673
|
page=page,
|
|
655
674
|
limit=row,
|
|
@@ -661,7 +680,8 @@ class ProjectService(AbstractService):
|
|
|
661
680
|
@error_handler()
|
|
662
681
|
def get_project_inference_simulator_model_list(
|
|
663
682
|
self,
|
|
664
|
-
|
|
683
|
+
project_public_id: Optional[str],
|
|
684
|
+
project_slug: Optional[str],
|
|
665
685
|
statuses: List[str],
|
|
666
686
|
row: int = 5,
|
|
667
687
|
page: int = 1,
|
|
@@ -669,22 +689,7 @@ class ProjectService(AbstractService):
|
|
|
669
689
|
data: Optional[
|
|
670
690
|
PaginatedEntityList[InferenceSimulatorModelDto]] = self.__thestage_api_client.get_inference_simulator_model_list_for_project(
|
|
671
691
|
statuses=statuses,
|
|
672
|
-
|
|
673
|
-
page=page,
|
|
674
|
-
limit=row,
|
|
675
|
-
)
|
|
676
|
-
|
|
677
|
-
return data
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
@error_handler()
|
|
681
|
-
def get_project_task_list(
|
|
682
|
-
self,
|
|
683
|
-
project_slug: str,
|
|
684
|
-
row: int = 5,
|
|
685
|
-
page: int = 1,
|
|
686
|
-
) -> PaginatedEntityList[TaskDto]:
|
|
687
|
-
data: Optional[PaginatedEntityList[TaskDto]] = self.__thestage_api_client.get_task_list_for_project(
|
|
692
|
+
project_public_id=project_public_id,
|
|
688
693
|
project_slug=project_slug,
|
|
689
694
|
page=page,
|
|
690
695
|
limit=row,
|
|
@@ -696,7 +701,7 @@ class ProjectService(AbstractService):
|
|
|
696
701
|
@error_handler()
|
|
697
702
|
def checkout_project(
|
|
698
703
|
self,
|
|
699
|
-
|
|
704
|
+
task_public_id: Optional[str],
|
|
700
705
|
branch_name: Optional[str],
|
|
701
706
|
):
|
|
702
707
|
config = self.__config_provider.get_config()
|
|
@@ -706,21 +711,21 @@ class ProjectService(AbstractService):
|
|
|
706
711
|
raise typer.Exit(1)
|
|
707
712
|
|
|
708
713
|
target_commit_hash: Optional[str] = None
|
|
709
|
-
if
|
|
714
|
+
if task_public_id:
|
|
710
715
|
task_view_response: Optional[TaskViewResponse] = None
|
|
711
716
|
try:
|
|
712
|
-
task_view_response = self.__thestage_api_client.get_task(
|
|
717
|
+
task_view_response = self.__thestage_api_client.get_task(task_public_id=task_public_id)
|
|
713
718
|
except HttpClientException as e:
|
|
714
719
|
if e.get_status_code() == 400:
|
|
715
|
-
typer.echo(f"Task {
|
|
720
|
+
typer.echo(f"Task {task_public_id} was not found")
|
|
716
721
|
# overriding arguments here
|
|
717
|
-
branch_name = str(
|
|
718
|
-
|
|
722
|
+
branch_name = str(task_public_id)
|
|
723
|
+
task_public_id = None
|
|
719
724
|
|
|
720
725
|
if task_view_response and task_view_response.task:
|
|
721
726
|
target_commit_hash = task_view_response.task.commit_hash
|
|
722
727
|
if not target_commit_hash:
|
|
723
|
-
typer.echo(f"Provided task ({
|
|
728
|
+
typer.echo(f"Provided task ({task_public_id}) has no commit hash") # possible legacy problems
|
|
724
729
|
raise typer.Exit(1)
|
|
725
730
|
|
|
726
731
|
is_commit_allowed: bool = True
|
|
@@ -833,48 +838,40 @@ class ProjectService(AbstractService):
|
|
|
833
838
|
|
|
834
839
|
|
|
835
840
|
@error_handler()
|
|
836
|
-
def set_default_container(
|
|
841
|
+
def set_default_container(
|
|
842
|
+
self,
|
|
843
|
+
container_public_id: Optional[str],
|
|
844
|
+
container_slug: Optional[str],
|
|
845
|
+
):
|
|
837
846
|
project_config: ProjectConfig = self.__config_provider.read_project_config()
|
|
838
847
|
|
|
839
848
|
if project_config is None:
|
|
840
849
|
typer.echo(f"No project found in working directory")
|
|
841
850
|
raise typer.Exit(1)
|
|
842
851
|
|
|
843
|
-
|
|
852
|
+
container: Optional[DockerContainerDto] = None
|
|
853
|
+
if container_slug or container_public_id:
|
|
844
854
|
container: DockerContainerDto = self.__thestage_api_client.get_container(
|
|
845
|
-
|
|
855
|
+
container_public_id=container_public_id,
|
|
856
|
+
container_slug=container_slug,
|
|
846
857
|
)
|
|
847
858
|
if container is None:
|
|
848
|
-
typer.echo(f"Could not find container '{
|
|
859
|
+
typer.echo(f"Could not find container '{container_slug or container_public_id}'")
|
|
849
860
|
raise typer.Exit(1)
|
|
850
861
|
|
|
851
|
-
if container.
|
|
852
|
-
typer.echo(f"Provided container '{
|
|
862
|
+
if container.project.public_id != project_config.public_id:
|
|
863
|
+
typer.echo(f"Provided container '{container_slug or container_public_id}' is not related to current project '{project_config.public_id}'")
|
|
853
864
|
raise typer.Exit(1)
|
|
854
865
|
|
|
855
866
|
if container.frontend_status.status_key != DockerContainerStatus.RUNNING:
|
|
856
|
-
typer.echo(f"Note: provided container '{
|
|
867
|
+
typer.echo(f"Note: provided container '{container_slug or container_public_id}' is in status '{container.frontend_status.status_translation}'")
|
|
857
868
|
|
|
858
|
-
project_config.
|
|
869
|
+
project_config.default_container_public_id = container.public_id if container else None
|
|
859
870
|
project_config.prompt_for_default_container = False
|
|
860
871
|
self.__config_provider.save_project_config(project_config=project_config)
|
|
861
872
|
typer.echo("Default container settings were updated")
|
|
862
873
|
|
|
863
874
|
|
|
864
|
-
@error_handler()
|
|
865
|
-
def unset_default_container(self):
|
|
866
|
-
project_config: ProjectConfig = self.__config_provider.read_project_config()
|
|
867
|
-
|
|
868
|
-
if project_config is None:
|
|
869
|
-
typer.echo(f"No project found in working directory")
|
|
870
|
-
raise typer.Exit(1)
|
|
871
|
-
|
|
872
|
-
project_config.default_container_uid = None
|
|
873
|
-
project_config.prompt_for_default_container = True # True or False?
|
|
874
|
-
self.__config_provider.save_project_config(project_config=project_config)
|
|
875
|
-
typer.echo("Default container settings were updated")
|
|
876
|
-
|
|
877
|
-
|
|
878
875
|
@error_handler()
|
|
879
876
|
def print_project_config(self):
|
|
880
877
|
project_config: ProjectConfig = self.__config_provider.read_project_config()
|
|
@@ -888,10 +885,13 @@ class ProjectService(AbstractService):
|
|
|
888
885
|
typer.echo(tabulate(
|
|
889
886
|
[
|
|
890
887
|
[
|
|
891
|
-
"Project
|
|
888
|
+
"Project ID", project_config.public_id
|
|
892
889
|
],
|
|
893
890
|
[
|
|
894
|
-
"
|
|
891
|
+
"Project name", project_config.slug
|
|
892
|
+
],
|
|
893
|
+
[
|
|
894
|
+
"Default docker container ID", project_config.default_container_public_id if project_config.default_container_public_id else "<None>"
|
|
895
895
|
],
|
|
896
896
|
[
|
|
897
897
|
"Deploy key path", project_config.deploy_key_path if is_deploy_key_exists else "<None>"
|
|
@@ -913,15 +913,19 @@ class ProjectService(AbstractService):
|
|
|
913
913
|
if project_config is None:
|
|
914
914
|
return None
|
|
915
915
|
|
|
916
|
+
if project_config.public_id is None:
|
|
917
|
+
project = self.__thestage_api_client.get_project(public_id=None, slug=project_config.slug)
|
|
918
|
+
project_config.public_id = project.public_id
|
|
919
|
+
self.__config_provider.save_project_config(project_config=project_config)
|
|
920
|
+
|
|
916
921
|
if not Path(project_config.deploy_key_path).is_file():
|
|
917
922
|
deploy_ssh_key = self.__thestage_api_client.get_project_deploy_ssh_key(
|
|
918
|
-
|
|
923
|
+
public_id=project_config.public_id,
|
|
919
924
|
)
|
|
920
925
|
|
|
921
926
|
deploy_key_path = self.__config_provider.save_project_deploy_ssh_key(
|
|
922
927
|
deploy_ssh_key=deploy_ssh_key,
|
|
923
|
-
|
|
924
|
-
project_id=project_config.id,
|
|
928
|
+
project_public_id=project_config.public_id,
|
|
925
929
|
)
|
|
926
930
|
|
|
927
931
|
project_config.deploy_key_path = deploy_key_path
|
|
@@ -933,11 +937,13 @@ class ProjectService(AbstractService):
|
|
|
933
937
|
@error_handler()
|
|
934
938
|
def project_deploy_inference_simulator_model_to_instance(
|
|
935
939
|
self,
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
940
|
+
model_public_id: Optional[str] = None,
|
|
941
|
+
model_slug: Optional[str] = None,
|
|
942
|
+
rented_instance_public_id: Optional[str] = None,
|
|
943
|
+
rented_instance_slug: Optional[str] = None,
|
|
944
|
+
self_hosted_instance_public_id: Optional[str] = None,
|
|
945
|
+
self_hosted_instance_slug: Optional[str] = None,
|
|
946
|
+
) -> str:
|
|
941
947
|
config = self.__config_provider.get_config()
|
|
942
948
|
project_config: ProjectConfig = self.__get_fixed_project_config()
|
|
943
949
|
if not project_config:
|
|
@@ -946,26 +952,30 @@ class ProjectService(AbstractService):
|
|
|
946
952
|
{"path": config.runtime.working_directory}))
|
|
947
953
|
raise typer.Exit(1)
|
|
948
954
|
|
|
949
|
-
|
|
950
|
-
|
|
955
|
+
instance_args_count = sum(v is not None for v in [rented_instance_public_id, rented_instance_slug, self_hosted_instance_public_id, self_hosted_instance_slug])
|
|
956
|
+
if instance_args_count != 1:
|
|
957
|
+
typer.echo("Please provide a single instance (rented or self-hosted) identifier - name or ID.")
|
|
951
958
|
raise typer.Exit(1)
|
|
952
959
|
|
|
953
|
-
|
|
954
|
-
|
|
960
|
+
model_args_count = sum(v is not None for v in [model_public_id, model_slug])
|
|
961
|
+
if model_args_count != 1:
|
|
962
|
+
typer.echo("Please provide a single model identifier - name or ID.")
|
|
955
963
|
raise typer.Exit(1)
|
|
956
964
|
|
|
957
|
-
typer.echo(
|
|
965
|
+
typer.echo(f"Creating inference simulator")
|
|
958
966
|
deploy_model_to_instance_response: DeployInferenceModelToInstanceResponse = self.__thestage_api_client.deploy_inference_model_to_instance(
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
967
|
+
model_public_id=model_public_id,
|
|
968
|
+
model_slug=model_slug,
|
|
969
|
+
rented_instance_public_id=rented_instance_public_id,
|
|
970
|
+
rented_instance_slug=rented_instance_slug,
|
|
971
|
+
self_hosted_instance_public_id=self_hosted_instance_public_id,
|
|
972
|
+
self_hosted_instance_slug=self_hosted_instance_slug,
|
|
963
973
|
)
|
|
964
974
|
if deploy_model_to_instance_response:
|
|
965
975
|
if deploy_model_to_instance_response.message:
|
|
966
976
|
typer.echo(deploy_model_to_instance_response.message)
|
|
967
977
|
if deploy_model_to_instance_response.is_success:
|
|
968
|
-
typer.echo("Inference simulator has been scheduled to run successfully.")
|
|
978
|
+
typer.echo(f"Inference simulator '{deploy_model_to_instance_response.inferenceSimulatorPublicId}' has been scheduled to run successfully.")
|
|
969
979
|
else:
|
|
970
980
|
typer.echo(__(
|
|
971
981
|
'Inference simulator failed to run with an error: %server_massage%',
|
|
@@ -976,11 +986,14 @@ class ProjectService(AbstractService):
|
|
|
976
986
|
typer.echo(__("Inference simulator failed to run with an error"))
|
|
977
987
|
raise typer.Exit(1)
|
|
978
988
|
|
|
989
|
+
return deploy_model_to_instance_response.inferenceSimulatorPublicId
|
|
990
|
+
|
|
979
991
|
|
|
980
992
|
@error_handler()
|
|
981
993
|
def project_deploy_inference_simulator_model_to_sagemaker(
|
|
982
994
|
self,
|
|
983
|
-
|
|
995
|
+
model_public_id: Optional[str] = None,
|
|
996
|
+
model_slug: Optional[str] = None,
|
|
984
997
|
arn: Optional[str] = None,
|
|
985
998
|
instance_type: Optional[str] = None,
|
|
986
999
|
initial_variant_weight: Optional[float] = 1.0,
|
|
@@ -1013,7 +1026,8 @@ class ProjectService(AbstractService):
|
|
|
1013
1026
|
raise typer.Exit(1)
|
|
1014
1027
|
|
|
1015
1028
|
deploy_model_to_sagemaker_response: DeployInferenceModelToSagemakerResponse = self.__thestage_api_client.deploy_inference_model_to_sagemaker(
|
|
1016
|
-
|
|
1029
|
+
model_public_id=model_public_id,
|
|
1030
|
+
model_slug=model_slug,
|
|
1017
1031
|
arn=arn,
|
|
1018
1032
|
)
|
|
1019
1033
|
|
|
@@ -1041,7 +1055,7 @@ class ProjectService(AbstractService):
|
|
|
1041
1055
|
},
|
|
1042
1056
|
}
|
|
1043
1057
|
|
|
1044
|
-
sm_model_name = f"{
|
|
1058
|
+
sm_model_name = f"{model_slug}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
|
|
1045
1059
|
create_model_response = sm_client.create_model(
|
|
1046
1060
|
ModelName=sm_model_name,
|
|
1047
1061
|
ExecutionRoleArn=arn,
|
|
@@ -1049,7 +1063,7 @@ class ProjectService(AbstractService):
|
|
|
1049
1063
|
)
|
|
1050
1064
|
typer.echo(f"Model created successfully. Model ARN: {create_model_response['ModelArn']}")
|
|
1051
1065
|
|
|
1052
|
-
endpoint_config_name = f"{
|
|
1066
|
+
endpoint_config_name = f"{model_slug}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
|
|
1053
1067
|
create_endpoint_config_response = sm_client.create_endpoint_config(
|
|
1054
1068
|
EndpointConfigName=endpoint_config_name,
|
|
1055
1069
|
ProductionVariants=[
|
|
@@ -1065,7 +1079,7 @@ class ProjectService(AbstractService):
|
|
|
1065
1079
|
typer.echo(
|
|
1066
1080
|
f"Endpoint configuration created successfully. Endpoint Config ARN: {create_endpoint_config_response['EndpointConfigArn']}")
|
|
1067
1081
|
|
|
1068
|
-
endpoint_name = f"{
|
|
1082
|
+
endpoint_name = f"{model_slug}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
|
|
1069
1083
|
create_endpoint_response = sm_client.create_endpoint(
|
|
1070
1084
|
EndpointName=endpoint_name,
|
|
1071
1085
|
EndpointConfigName=endpoint_config_name,
|
|
@@ -1128,13 +1142,13 @@ class ProjectService(AbstractService):
|
|
|
1128
1142
|
|
|
1129
1143
|
|
|
1130
1144
|
@error_handler()
|
|
1131
|
-
def print_inference_simulator_list(self,
|
|
1132
|
-
if not
|
|
1145
|
+
def print_inference_simulator_list(self, project_public_id, project_slug, statuses, row, page):
|
|
1146
|
+
if not project_public_id and not project_slug:
|
|
1133
1147
|
project_config: ProjectConfig = self.__config_provider.read_project_config()
|
|
1134
1148
|
if not project_config:
|
|
1135
|
-
typer.echo(__("Provide the project
|
|
1149
|
+
typer.echo(__("Provide the project identifier or run this command from within an initialized project directory"))
|
|
1136
1150
|
raise typer.Exit(1)
|
|
1137
|
-
|
|
1151
|
+
project_public_id = project_config.public_id
|
|
1138
1152
|
|
|
1139
1153
|
inference_simulator_status_map = self.__thestage_api_client.get_inference_simulator_business_status_map()
|
|
1140
1154
|
|
|
@@ -1167,7 +1181,8 @@ class ProjectService(AbstractService):
|
|
|
1167
1181
|
self.print(
|
|
1168
1182
|
func_get_data=self.get_project_inference_simulator_list,
|
|
1169
1183
|
func_special_params={
|
|
1170
|
-
'
|
|
1184
|
+
'project_public_id': project_public_id,
|
|
1185
|
+
'project_slug': project_slug,
|
|
1171
1186
|
'statuses': backend_statuses,
|
|
1172
1187
|
},
|
|
1173
1188
|
mapper=ProjectInferenceSimulatorMapper(),
|
|
@@ -1180,13 +1195,13 @@ class ProjectService(AbstractService):
|
|
|
1180
1195
|
|
|
1181
1196
|
|
|
1182
1197
|
@error_handler()
|
|
1183
|
-
def print_inference_simulator_model_list(self,
|
|
1184
|
-
if not
|
|
1198
|
+
def print_inference_simulator_model_list(self, project_public_id, project_slug, statuses, row, page):
|
|
1199
|
+
if not project_public_id and not project_slug:
|
|
1185
1200
|
project_config: ProjectConfig = self.__config_provider.read_project_config()
|
|
1186
1201
|
if not project_config:
|
|
1187
|
-
typer.echo(__("Provide the project
|
|
1202
|
+
typer.echo(__("Provide the project identifier or run this command from within an initialized project directory"))
|
|
1188
1203
|
raise typer.Exit(1)
|
|
1189
|
-
|
|
1204
|
+
project_public_id = project_config.public_id
|
|
1190
1205
|
|
|
1191
1206
|
inference_simulator_model_status_map = self.__thestage_api_client.get_inference_simulator_model_business_status_map()
|
|
1192
1207
|
|
|
@@ -1219,30 +1234,32 @@ class ProjectService(AbstractService):
|
|
|
1219
1234
|
self.print(
|
|
1220
1235
|
func_get_data=self.get_project_inference_simulator_model_list,
|
|
1221
1236
|
func_special_params={
|
|
1222
|
-
'
|
|
1237
|
+
'project_public_id': project_public_id,
|
|
1238
|
+
'project_slug': project_slug,
|
|
1223
1239
|
'statuses': backend_statuses,
|
|
1224
1240
|
},
|
|
1225
1241
|
mapper=ProjectInferenceSimulatorModelMapper(),
|
|
1226
1242
|
headers=list(map(lambda x: x.alias, ProjectInferenceSimulatorModelEntity.model_fields.values())),
|
|
1227
1243
|
row=row,
|
|
1228
1244
|
page=page,
|
|
1229
|
-
max_col_width=[100, 100, 100, 100,
|
|
1245
|
+
max_col_width=[100, 100, 100, 100, 25],
|
|
1230
1246
|
show_index="never",
|
|
1231
1247
|
)
|
|
1232
1248
|
|
|
1233
1249
|
|
|
1234
|
-
def print_task_list(self,
|
|
1235
|
-
if not
|
|
1250
|
+
def print_task_list(self, project_public_id: Optional[str], project_slug: Optional[str], row, page):
|
|
1251
|
+
if not project_slug and not project_public_id:
|
|
1236
1252
|
project_config: ProjectConfig = self.__config_provider.read_project_config()
|
|
1237
1253
|
if not project_config:
|
|
1238
|
-
typer.echo(__("Provide the project
|
|
1254
|
+
typer.echo(__("Provide the project identifier or run this command from within an initialized project directory"))
|
|
1239
1255
|
raise typer.Exit(1)
|
|
1240
|
-
|
|
1256
|
+
project_public_id = project_config.public_id
|
|
1241
1257
|
|
|
1242
1258
|
self.print(
|
|
1243
1259
|
func_get_data=self.get_project_task_list,
|
|
1244
1260
|
func_special_params={
|
|
1245
|
-
'
|
|
1261
|
+
'project_public_id': project_public_id,
|
|
1262
|
+
'project_slug': project_slug,
|
|
1246
1263
|
},
|
|
1247
1264
|
mapper=ProjectTaskMapper(),
|
|
1248
1265
|
headers=list(map(lambda x: x.alias, ProjectTaskEntity.model_fields.values())),
|
|
@@ -1251,3 +1268,20 @@ class ProjectService(AbstractService):
|
|
|
1251
1268
|
max_col_width=[100, 100, 100, 100, 100, 100, 100, 100],
|
|
1252
1269
|
show_index="never",
|
|
1253
1270
|
)
|
|
1271
|
+
|
|
1272
|
+
@error_handler()
|
|
1273
|
+
def get_project_task_list(
|
|
1274
|
+
self,
|
|
1275
|
+
project_public_id: Optional[str],
|
|
1276
|
+
project_slug: Optional[str],
|
|
1277
|
+
row: int = 5,
|
|
1278
|
+
page: int = 1,
|
|
1279
|
+
) -> PaginatedEntityList[TaskDto]:
|
|
1280
|
+
data: Optional[PaginatedEntityList[TaskDto]] = self.__thestage_api_client.get_task_list_for_project(
|
|
1281
|
+
project_public_id=project_public_id,
|
|
1282
|
+
project_slug=project_slug,
|
|
1283
|
+
page=page,
|
|
1284
|
+
limit=row,
|
|
1285
|
+
)
|
|
1286
|
+
|
|
1287
|
+
return data
|