thestage 0.6.8__tar.gz → 0.7.0__tar.gz
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-0.6.8 → thestage-0.7.0}/PKG-INFO +1 -1
- {thestage-0.6.8 → thestage-0.7.0}/pyproject.toml +1 -1
- {thestage-0.6.8 → thestage-0.7.0}/thestage/__init__.py +1 -1
- {thestage-0.6.8 → thestage-0.7.0}/thestage/cli_command.py +3 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/business/container_service.py +121 -1
- thestage-0.7.0/thestage/docker_container/business/mapper/image_mapper.py +16 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/communication/docker_command.py +178 -9
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/communication/docker_container_api_client.py +42 -2
- thestage-0.7.0/thestage/docker_container/communication/image_command.py +40 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/dto/container_response.py +7 -0
- thestage-0.7.0/thestage/docker_container/dto/docker_container_create_request.py +28 -0
- thestage-0.7.0/thestage/docker_container/dto/docker_container_create_response.py +11 -0
- thestage-0.7.0/thestage/docker_container/dto/docker_image_list_request.py +11 -0
- thestage-0.7.0/thestage/docker_container/dto/docker_image_list_response.py +13 -0
- thestage-0.7.0/thestage/docker_container/dto/image_entity.py +14 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/helpers/error_handler.py +1 -1
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/business/inference_model_service.py +6 -6
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/business/inference_simulator_service.py +3 -3
- {thestage-0.6.8 → thestage-0.7.0}/thestage/main.py +7 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/project/business/project_service.py +3 -3
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/business/task_service.py +5 -2
- {thestage-0.6.8 → thestage-0.7.0}/LICENSE.txt +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/README.md +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/.env +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/__main__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/cli_command_helper.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/color_scheme/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/color_scheme/color_scheme.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/config/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/config/business/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/config/business/app_config_service.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/config/business/config_provider.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/config/business/config_storage.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/config/business/validation_service.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/config/communication/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/config/communication/config_command.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/config/dto/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/config/dto/config_entity.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/config/dto/remote_server_config.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/config/env_base.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/connect/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/connect/business/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/connect/business/connect_service.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/connect/business/remote_server_service.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/connect/communication/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/connect/communication/connect_api_client.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/connect/dto/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/connect/dto/add_ssh_key_to_user_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/connect/dto/add_ssh_key_to_user_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/connect/dto/add_ssh_public_key_to_instance_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/connect/dto/add_ssh_public_key_to_instance_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/connect/dto/connect_resolve_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/connect/dto/is_user_has_public_ssh_key_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/connect/dto/is_user_has_public_ssh_key_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/controllers/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/controllers/base_controller.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/controllers/utils_controller.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/debug_main.dist.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/business/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/business/mapper/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/business/mapper/container_mapper.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/communication/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/dto/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/dto/container_action_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/dto/container_entity.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/dto/docker_container_list_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/dto/docker_container_list_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/dto/docker_container_mapping.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/dto/enum/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/dto/enum/container_pending_action.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/docker_container/dto/enum/container_status.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/exceptions/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/exceptions/auth_exception.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/exceptions/base_exception.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/exceptions/business_logic_exception.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/exceptions/config_exception.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/exceptions/file_system_exception.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/exceptions/git_access_exception.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/exceptions/log_polling_exception.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/exceptions/remote_server_exception.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/git/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/git/business/ProgressPrinter.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/git/business/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/git/communication/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/git/communication/git_client.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/global_dto/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/global_dto/enums/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/global_dto/enums/order_direction_type.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/global_dto/enums/shell_type.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/global_dto/enums/tail_output_type.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/global_dto/enums/yes_no_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/global_dto/file_item.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/helpers/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/helpers/exception_hook.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/helpers/logger/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/helpers/logger/app_logger.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/helpers/ssh_util.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/i18n/en_GB/messages.po +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/i18n/translation.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/business/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/business/mapper/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/business/mapper/inference_model_mapper.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/communication/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/communication/inference_model_api_client.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/communication/inference_model_command.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/dto/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/dto/deploy_inference_model_to_instance_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/dto/deploy_inference_model_to_instance_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/dto/deploy_inference_model_to_sagemaker_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/dto/deploy_inference_model_to_sagemaker_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/dto/enum/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/dto/enum/inference_model_status.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/dto/inference_model.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/dto/inference_model_entity.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/dto/inference_simulator_model_list_for_project_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/dto/inference_simulator_model_list_for_project_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/dto/inference_simulator_model_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/dto/push_inference_simulator_model_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_model/dto/push_inference_simulator_model_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/business/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/business/mapper/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/business/mapper/inference_simulator_mapper.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/communication/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/communication/inference_simulator_api_client.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/communication/inference_simulator_command.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/dto/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/dto/enum/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/dto/enum/inference_simulator_status.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/dto/get_inference_simulator_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/dto/get_inference_simulator_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/dto/inference_simulator.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/dto/inference_simulator_entity.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/dto/inference_simulator_list_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/dto/inference_simulator_list_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/dto/inference_simulator_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/dto/start_inference_simulator_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/inference_simulator/dto/start_inference_simulator_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/business/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/business/instance_service.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/business/mapper/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/business/mapper/rented_instance_mapper.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/business/mapper/selfhosted_instance_mapper.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/communication/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/communication/instance_api_client.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/communication/instance_command.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/dto/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/dto/enum/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/dto/enum/cpu_type.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/dto/enum/gpu_name.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/dto/enum/instance_rented_status.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/dto/enum/provider_name.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/dto/enum/selfhosted_status.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/dto/instance_detected_gpus.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/dto/instance_rented_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/dto/rented_instance.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/dto/self_hosted_instance.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/instance/dto/selfhosted_instance_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/business/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/business/logging_service.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/byte_print_style.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/communication/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/communication/logging_api_client.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/dto/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/dto/docker_container_log_stream_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/dto/log_message.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/dto/log_polling_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/dto/log_polling_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/dto/log_type.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/dto/task_log_stream_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/dto/user_logs_query_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/dto/user_logs_query_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/logging/logging_constants.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/project/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/project/business/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/project/communication/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/project/communication/project_api_client.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/project/communication/project_command.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/project/dto/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/project/dto/get_deploy_ssh_key_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/project/dto/get_deploy_ssh_key_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/project/dto/project_config.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/project/dto/project_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/.env +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/abstract_mapper.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/abstract_service.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/clients/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/clients/thestage_api/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/clients/thestage_api/core/api_client_core.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/clients/thestage_api/core/http_client_exception.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/clients/thestage_api/dtos/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/clients/thestage_api/dtos/base_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/clients/thestage_api/dtos/entity_filter_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/clients/thestage_api/dtos/frontend_status.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/clients/thestage_api/dtos/installed_service.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/clients/thestage_api/dtos/paginated_entity_list.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/clients/thestage_api/dtos/pagination_data.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/clients/thestage_api/dtos/sftp_path_helper.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/clients/thestage_api/dtos/validate_token_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/filesystem_service.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/services/service_factory.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/business/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/business/mapper/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/business/mapper/task_mapper.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/communication/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/communication/task_api_client.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/communication/task_command.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/dto/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/dto/enum/__init__.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/dto/enum/task_execution_status.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/dto/enum/task_status.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/dto/list_for_project_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/dto/list_for_project_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/dto/run_task_request.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/dto/run_task_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/dto/status_localized_map_response.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/dto/task.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/dto/task_entity.py +0 -0
- {thestage-0.6.8 → thestage-0.7.0}/thestage/task/dto/view_response.py +0 -0
|
@@ -27,10 +27,13 @@ class CliCommand(str, Enum):
|
|
|
27
27
|
CONTAINER_CONNECT = "CONTAINER_CONNECT"
|
|
28
28
|
CONTAINER_UPLOAD = "CONTAINER_UPLOAD"
|
|
29
29
|
CONTAINER_DOWNLOAD = "CONTAINER_DOWNLOAD"
|
|
30
|
+
CONTAINER_CREATE = "CONTAINER_CREATE"
|
|
30
31
|
CONTAINER_START = "CONTAINER_START"
|
|
31
32
|
CONTAINER_STOP = "CONTAINER_STOP"
|
|
33
|
+
CONTAINER_DELETE = "CONTAINER_DELETE"
|
|
32
34
|
CONTAINER_RESTART = "CONTAINER_RESTART"
|
|
33
35
|
CONTAINER_LOGS = "CONTAINER_LOGS"
|
|
36
|
+
CONTAINER_IMAGE_LS = "CONTAINER_IMAGE_LS"
|
|
34
37
|
INSTANCE_RENTED_LS = "INSTANCE_RENTED_LS"
|
|
35
38
|
INSTANCE_RENTED_CONNECT = "INSTANCE_RENTED_CONNECT"
|
|
36
39
|
INSTANCE_SELF_HOSTED_LS = "INSTANCE_SELF_HOSTED_LS"
|
|
@@ -7,19 +7,24 @@ import typer
|
|
|
7
7
|
|
|
8
8
|
from thestage.color_scheme.color_scheme import ColorScheme
|
|
9
9
|
from thestage.connect.communication.connect_api_client import ConnectApiClient
|
|
10
|
+
from thestage.docker_container.business.mapper.image_mapper import ImageMapper
|
|
10
11
|
from thestage.docker_container.communication.docker_container_api_client import DockerContainerApiClient
|
|
11
12
|
from thestage.docker_container.dto.container_entity import DockerContainerEntity
|
|
12
13
|
from thestage.docker_container.dto.container_action_request import DockerContainerActionRequest
|
|
14
|
+
from thestage.docker_container.dto.docker_container_create_request import DockerContainerCreateRequest, \
|
|
15
|
+
DockerContainerMappings
|
|
13
16
|
from thestage.docker_container.dto.enum.container_pending_action import DockerContainerAction
|
|
14
17
|
from thestage.docker_container.dto.enum.container_status import DockerContainerStatus
|
|
18
|
+
from thestage.docker_container.dto.image_entity import DockerImageEntity
|
|
15
19
|
from thestage.global_dto.enums.shell_type import ShellType
|
|
20
|
+
from thestage.project.dto.project_config import ProjectConfig
|
|
16
21
|
from thestage.services.clients.thestage_api.dtos.paginated_entity_list import PaginatedEntityList
|
|
17
22
|
from thestage.docker_container.business.mapper.container_mapper import ContainerMapper
|
|
18
23
|
from thestage.services.filesystem_service import FileSystemService
|
|
19
24
|
from thestage.connect.business.remote_server_service import RemoteServerService
|
|
20
25
|
from thestage.i18n.translation import __
|
|
21
26
|
from thestage.services.abstract_service import AbstractService
|
|
22
|
-
from thestage.docker_container.dto.container_response import DockerContainerDto
|
|
27
|
+
from thestage.docker_container.dto.container_response import DockerContainerDto, DockerImageDto
|
|
23
28
|
from thestage.helpers.error_handler import error_handler
|
|
24
29
|
from thestage.config.business.config_provider import ConfigProvider
|
|
25
30
|
|
|
@@ -118,6 +123,7 @@ class ContainerService(AbstractService):
|
|
|
118
123
|
|
|
119
124
|
return list
|
|
120
125
|
|
|
126
|
+
|
|
121
127
|
# TODO delete this proxy method
|
|
122
128
|
@error_handler()
|
|
123
129
|
def get_container(
|
|
@@ -456,3 +462,117 @@ class ContainerService(AbstractService):
|
|
|
456
462
|
|
|
457
463
|
if result.is_success:
|
|
458
464
|
typer.echo(f'Docker container action scheduled: {action.value}')
|
|
465
|
+
|
|
466
|
+
@error_handler()
|
|
467
|
+
def create_docker_container(
|
|
468
|
+
self,
|
|
469
|
+
project_public_id: Optional[str],
|
|
470
|
+
project_slug: Optional[str],
|
|
471
|
+
container_slug: str,
|
|
472
|
+
rented_instance_public_id: Optional[str],
|
|
473
|
+
rented_instance_slug: Optional[str],
|
|
474
|
+
self_hosted_instance_public_id: Optional[str],
|
|
475
|
+
self_hosted_instance_slug: Optional[str],
|
|
476
|
+
image_name: str,
|
|
477
|
+
cpu_number: Optional[int],
|
|
478
|
+
gpu_number: Optional[int],
|
|
479
|
+
volume_mappings: Optional[Dict[str, str]],
|
|
480
|
+
):
|
|
481
|
+
if not project_public_id and not project_slug:
|
|
482
|
+
project_config: ProjectConfig = self.__config_provider.read_project_config()
|
|
483
|
+
if not project_config:
|
|
484
|
+
typer.echo("Provide the project unique ID or name, or run this command from within an initialized project directory")
|
|
485
|
+
raise typer.Exit(1)
|
|
486
|
+
project_public_id = project_config.public_id
|
|
487
|
+
|
|
488
|
+
docker_images_paginated = self.get_image_list()
|
|
489
|
+
if not docker_images_paginated or not docker_images_paginated.entities:
|
|
490
|
+
typer.echo("No Docker images available")
|
|
491
|
+
raise typer.Exit(1)
|
|
492
|
+
|
|
493
|
+
selected_image = None
|
|
494
|
+
selection_pool = docker_images_paginated.entities
|
|
495
|
+
|
|
496
|
+
if image_name is not None:
|
|
497
|
+
matches = [img for img in selection_pool if img.image == image_name]
|
|
498
|
+
|
|
499
|
+
if len(matches) == 1:
|
|
500
|
+
selected_image = matches[0]
|
|
501
|
+
elif len(matches) > 1:
|
|
502
|
+
typer.echo(f"Multiple tags found for repository '{image_name}':")
|
|
503
|
+
selection_pool = matches
|
|
504
|
+
else:
|
|
505
|
+
typer.echo(f"Image '{image_name}' not found. Select from available images:")
|
|
506
|
+
|
|
507
|
+
if selected_image is None:
|
|
508
|
+
for idx, img in enumerate(selection_pool, start=1):
|
|
509
|
+
typer.echo(f"{idx}) {img.image}:{img.tag}")
|
|
510
|
+
|
|
511
|
+
choice_str = typer.prompt("Choose which image to use")
|
|
512
|
+
|
|
513
|
+
try:
|
|
514
|
+
choice_index = int(choice_str)
|
|
515
|
+
except ValueError:
|
|
516
|
+
typer.echo("Error: Invalid input. Enter a number.")
|
|
517
|
+
raise typer.Exit(1)
|
|
518
|
+
|
|
519
|
+
if not (1 <= choice_index <= len(selection_pool)):
|
|
520
|
+
typer.echo("Error: Choice out of range.")
|
|
521
|
+
raise typer.Exit(1)
|
|
522
|
+
|
|
523
|
+
selected_image = selection_pool[choice_index - 1]
|
|
524
|
+
|
|
525
|
+
request_params = DockerContainerCreateRequest(
|
|
526
|
+
instance_rented_public_id=rented_instance_public_id,
|
|
527
|
+
instance_rented_slug=rented_instance_slug,
|
|
528
|
+
selfhosted_instance_public_id=self_hosted_instance_public_id,
|
|
529
|
+
selfhosted_instance_slug=self_hosted_instance_slug,
|
|
530
|
+
project_public_id=project_public_id,
|
|
531
|
+
project_slug=project_slug,
|
|
532
|
+
container_slug=container_slug,
|
|
533
|
+
docker_image_id=selected_image.id,
|
|
534
|
+
assigned_cpus=cpu_number,
|
|
535
|
+
is_unlimited_cpus=cpu_number is None,
|
|
536
|
+
assigned_gpus=gpu_number,
|
|
537
|
+
is_unlimited_gpus=gpu_number is None,
|
|
538
|
+
mappings=DockerContainerMappings(directory_mappings=volume_mappings)
|
|
539
|
+
)
|
|
540
|
+
|
|
541
|
+
result = self.__docker_container_api_client.create_container(
|
|
542
|
+
request_params
|
|
543
|
+
)
|
|
544
|
+
if result.is_success:
|
|
545
|
+
typer.echo(f'Docker container creation scheduled.')
|
|
546
|
+
|
|
547
|
+
@error_handler()
|
|
548
|
+
def print_docker_image_list(
|
|
549
|
+
self,
|
|
550
|
+
row: int,
|
|
551
|
+
page: int,
|
|
552
|
+
):
|
|
553
|
+
typer.echo("Listing available Docker images:")
|
|
554
|
+
|
|
555
|
+
self.print(
|
|
556
|
+
func_get_data=self.get_image_list,
|
|
557
|
+
func_special_params={},
|
|
558
|
+
mapper=ImageMapper(),
|
|
559
|
+
headers=list(map(lambda x: x.alias, DockerImageEntity.model_fields.values())),
|
|
560
|
+
row=row,
|
|
561
|
+
page=page,
|
|
562
|
+
max_col_width=[50, 20],
|
|
563
|
+
show_index="never",
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
@error_handler()
|
|
567
|
+
def get_image_list(
|
|
568
|
+
self,
|
|
569
|
+
row: int = 5,
|
|
570
|
+
page: int = 1,
|
|
571
|
+
) -> PaginatedEntityList[DockerImageDto]:
|
|
572
|
+
|
|
573
|
+
list = self.__docker_container_api_client.get_docker_image_list(
|
|
574
|
+
page=page,
|
|
575
|
+
limit=row,
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
return list
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from thestage.docker_container.dto.container_response import DockerImageDto
|
|
4
|
+
from thestage.docker_container.dto.image_entity import DockerImageEntity
|
|
5
|
+
from thestage.services.abstract_mapper import AbstractMapper
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ImageMapper(AbstractMapper):
|
|
9
|
+
def build_entity(self, item: DockerImageDto) -> Optional[DockerImageEntity]:
|
|
10
|
+
if not item:
|
|
11
|
+
return None
|
|
12
|
+
|
|
13
|
+
return DockerImageEntity(
|
|
14
|
+
image=item.image or '',
|
|
15
|
+
tag=item.tag or '',
|
|
16
|
+
)
|
|
@@ -15,7 +15,6 @@ from thestage.logging.business.logging_service import LoggingService
|
|
|
15
15
|
|
|
16
16
|
app = typer.Typer(no_args_is_help=True, help=__("Manage containers"))
|
|
17
17
|
|
|
18
|
-
|
|
19
18
|
@app.command(name='ls', help=__("List containers"), **get_command_metadata(CliCommand.CONTAINER_LS))
|
|
20
19
|
def list_containers(
|
|
21
20
|
row: int = typer.Option(
|
|
@@ -289,7 +288,7 @@ def start_container(
|
|
|
289
288
|
check_command_permission(command_name)
|
|
290
289
|
|
|
291
290
|
if sum(v is not None for v in [container_public_id, container_slug]) != 1:
|
|
292
|
-
typer.echo("
|
|
291
|
+
typer.echo("Provide a single identifier for container - ID or name.")
|
|
293
292
|
raise typer.Exit(1)
|
|
294
293
|
|
|
295
294
|
service_factory = validate_config_and_get_service_factory()
|
|
@@ -301,7 +300,140 @@ def start_container(
|
|
|
301
300
|
action=DockerContainerAction.START
|
|
302
301
|
)
|
|
303
302
|
|
|
304
|
-
app_logger.info(f'Container
|
|
303
|
+
app_logger.info(f'Container is starting')
|
|
304
|
+
raise typer.Exit(0)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
@app.command(name="create", no_args_is_help=True, help=__("Create container"), **get_command_metadata(CliCommand.CONTAINER_CREATE))
|
|
308
|
+
def create_container(
|
|
309
|
+
project_public_id: Optional[str] = typer.Option(
|
|
310
|
+
None,
|
|
311
|
+
'--project-id',
|
|
312
|
+
'-pid',
|
|
313
|
+
help=__("Project ID. By default, project info is taken from the current directory"),
|
|
314
|
+
is_eager=False,
|
|
315
|
+
),
|
|
316
|
+
project_slug: Optional[str] = typer.Option(
|
|
317
|
+
None,
|
|
318
|
+
'--project-name',
|
|
319
|
+
'-pn',
|
|
320
|
+
help=__("Project name. By default, project info is taken from the current directory"),
|
|
321
|
+
is_eager=False,
|
|
322
|
+
),
|
|
323
|
+
working_directory: Optional[str] = typer.Option(
|
|
324
|
+
None,
|
|
325
|
+
"--working-directory",
|
|
326
|
+
"-wd",
|
|
327
|
+
help=__("Full path to working directory"),
|
|
328
|
+
show_default=False,
|
|
329
|
+
is_eager=False,
|
|
330
|
+
),
|
|
331
|
+
container_slug: Optional[str] = typer.Option(
|
|
332
|
+
None,
|
|
333
|
+
'--container-name',
|
|
334
|
+
'-cn',
|
|
335
|
+
help=__("Container name"),
|
|
336
|
+
is_eager=False,
|
|
337
|
+
),
|
|
338
|
+
rented_instance_public_id: Optional[str] = typer.Option(
|
|
339
|
+
None,
|
|
340
|
+
'--rented-instance-id',
|
|
341
|
+
'-rid',
|
|
342
|
+
help=__("Rented instance ID on which container will run"),
|
|
343
|
+
is_eager=False,
|
|
344
|
+
),
|
|
345
|
+
rented_instance_slug: Optional[str] = typer.Option(
|
|
346
|
+
None,
|
|
347
|
+
'--rented-instance-name',
|
|
348
|
+
'-rn',
|
|
349
|
+
help=__("Rented instance name on which container will run"),
|
|
350
|
+
is_eager=False,
|
|
351
|
+
),
|
|
352
|
+
self_hosted_instance_public_id: Optional[str] = typer.Option(
|
|
353
|
+
None,
|
|
354
|
+
'--self-hosted-instance-id',
|
|
355
|
+
'-sid',
|
|
356
|
+
help=__("Self-hosted instance ID on which container will run"),
|
|
357
|
+
is_eager=False,
|
|
358
|
+
),
|
|
359
|
+
self_hosted_instance_slug: Optional[str] = typer.Option(
|
|
360
|
+
None,
|
|
361
|
+
'--self-hosted-instance-name',
|
|
362
|
+
'-sn',
|
|
363
|
+
help=__("Self-hosted instance name on which container will run"),
|
|
364
|
+
is_eager=False,
|
|
365
|
+
),
|
|
366
|
+
image_name: Optional[str] = typer.Option(
|
|
367
|
+
None,
|
|
368
|
+
'--image',
|
|
369
|
+
'-i',
|
|
370
|
+
help=__("Docker image name. If not provided, you will be prompted to select from available images"),
|
|
371
|
+
is_eager=False,
|
|
372
|
+
),
|
|
373
|
+
gpu_number: Optional[int] = typer.Option(
|
|
374
|
+
None,
|
|
375
|
+
'--gpu-number',
|
|
376
|
+
'-gpun',
|
|
377
|
+
help=__("Number of assigned GPUs for container. No GPU limit by default"),
|
|
378
|
+
is_eager=False,
|
|
379
|
+
),
|
|
380
|
+
cpu_number: Optional[int] = typer.Option(
|
|
381
|
+
None,
|
|
382
|
+
'--cpu-number',
|
|
383
|
+
'-cpun',
|
|
384
|
+
help=__("Number of assigned CPUs for container. No CPU limit by default"),
|
|
385
|
+
is_eager=False,
|
|
386
|
+
),
|
|
387
|
+
volume_mounts: Optional[List[str]] = typer.Option(
|
|
388
|
+
None,
|
|
389
|
+
'--volume',
|
|
390
|
+
'-v',
|
|
391
|
+
help=__("Volume mounts. Can be used multiple times. Format: /host_dir:/container_dir"),
|
|
392
|
+
is_eager=False,
|
|
393
|
+
),
|
|
394
|
+
):
|
|
395
|
+
command_name = CliCommand.CONTAINER_CREATE
|
|
396
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
397
|
+
check_command_permission(command_name)
|
|
398
|
+
|
|
399
|
+
if sum(v is not None for v in [project_public_id, project_slug]) > 1:
|
|
400
|
+
typer.echo("Provide a single identifier for project - ID or name.")
|
|
401
|
+
raise typer.Exit(1)
|
|
402
|
+
|
|
403
|
+
if sum(v is not None for v in [rented_instance_public_id, rented_instance_slug, self_hosted_instance_public_id, self_hosted_instance_slug]) != 1:
|
|
404
|
+
typer.echo("Provide exactly one identifier (ID or Name) for either a rented or self-hosted instance.")
|
|
405
|
+
raise typer.Exit(1)
|
|
406
|
+
|
|
407
|
+
if not container_slug:
|
|
408
|
+
container_slug = typer.prompt("Enter container name")
|
|
409
|
+
|
|
410
|
+
volume_mappings_dict = {}
|
|
411
|
+
if volume_mounts:
|
|
412
|
+
for mount in volume_mounts:
|
|
413
|
+
if ":" not in mount:
|
|
414
|
+
typer.echo(f"Invalid volume format: {mount}. Expected host:container")
|
|
415
|
+
raise typer.Exit(1)
|
|
416
|
+
host_path, container_path = mount.split(":", 1)
|
|
417
|
+
volume_mappings_dict[host_path] = container_path
|
|
418
|
+
|
|
419
|
+
service_factory = validate_config_and_get_service_factory(working_directory=working_directory)
|
|
420
|
+
container_service: ContainerService = service_factory.get_container_service()
|
|
421
|
+
|
|
422
|
+
container_service.create_docker_container(
|
|
423
|
+
project_public_id=project_public_id,
|
|
424
|
+
project_slug=project_slug,
|
|
425
|
+
container_slug=container_slug,
|
|
426
|
+
rented_instance_public_id=rented_instance_public_id,
|
|
427
|
+
rented_instance_slug=rented_instance_slug,
|
|
428
|
+
self_hosted_instance_public_id=self_hosted_instance_public_id,
|
|
429
|
+
self_hosted_instance_slug=self_hosted_instance_slug,
|
|
430
|
+
image_name=image_name,
|
|
431
|
+
cpu_number=cpu_number,
|
|
432
|
+
gpu_number=gpu_number,
|
|
433
|
+
volume_mappings=volume_mappings_dict
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
app_logger.info(f'Container is creating')
|
|
305
437
|
raise typer.Exit(0)
|
|
306
438
|
|
|
307
439
|
|
|
@@ -327,7 +459,7 @@ def stop_container(
|
|
|
327
459
|
check_command_permission(command_name)
|
|
328
460
|
|
|
329
461
|
if sum(v is not None for v in [container_public_id, container_slug]) != 1:
|
|
330
|
-
typer.echo("
|
|
462
|
+
typer.echo("Provide a single identifier for container - ID or name.")
|
|
331
463
|
raise typer.Exit(1)
|
|
332
464
|
|
|
333
465
|
service_factory = validate_config_and_get_service_factory()
|
|
@@ -339,10 +471,47 @@ def stop_container(
|
|
|
339
471
|
action=DockerContainerAction.STOP
|
|
340
472
|
)
|
|
341
473
|
|
|
342
|
-
app_logger.info(f'Container
|
|
474
|
+
app_logger.info(f'Container is stopping')
|
|
343
475
|
raise typer.Exit(0)
|
|
344
476
|
|
|
345
477
|
|
|
478
|
+
@app.command(name="delete", no_args_is_help=True, help=__("Delete container"), **get_command_metadata(CliCommand.CONTAINER_DELETE))
|
|
479
|
+
def delete_container(
|
|
480
|
+
container_public_id: str = typer.Option(
|
|
481
|
+
None,
|
|
482
|
+
'--container-id',
|
|
483
|
+
'-cid',
|
|
484
|
+
help=__("Container ID"),
|
|
485
|
+
is_eager=False,
|
|
486
|
+
),
|
|
487
|
+
container_slug: str = typer.Option(
|
|
488
|
+
None,
|
|
489
|
+
'--container-name',
|
|
490
|
+
'-cn',
|
|
491
|
+
help=__("Container name"),
|
|
492
|
+
is_eager=False,
|
|
493
|
+
),
|
|
494
|
+
):
|
|
495
|
+
command_name = CliCommand.CONTAINER_DELETE
|
|
496
|
+
app_logger.info(f'Running {command_name} from {get_current_directory()}')
|
|
497
|
+
check_command_permission(command_name)
|
|
498
|
+
|
|
499
|
+
if sum(v is not None for v in [container_public_id, container_slug]) != 1:
|
|
500
|
+
typer.echo("Provide a single identifier for container - ID or name.")
|
|
501
|
+
raise typer.Exit(1)
|
|
502
|
+
|
|
503
|
+
service_factory = validate_config_and_get_service_factory()
|
|
504
|
+
container_service: ContainerService = service_factory.get_container_service()
|
|
505
|
+
|
|
506
|
+
container_service.request_docker_container_action(
|
|
507
|
+
container_public_id=container_public_id,
|
|
508
|
+
container_slug=container_slug,
|
|
509
|
+
action=DockerContainerAction.DELETE
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
app_logger.info(f'Container is deleting')
|
|
513
|
+
raise typer.Exit(0)
|
|
514
|
+
|
|
346
515
|
@app.command(name="restart", no_args_is_help=True, help=__("Restart container"), **get_command_metadata(CliCommand.CONTAINER_RESTART))
|
|
347
516
|
def restart_container(
|
|
348
517
|
container_public_id: str = typer.Option(
|
|
@@ -365,7 +534,7 @@ def restart_container(
|
|
|
365
534
|
check_command_permission(command_name)
|
|
366
535
|
|
|
367
536
|
if sum(v is not None for v in [container_public_id, container_slug]) != 1:
|
|
368
|
-
typer.echo("
|
|
537
|
+
typer.echo("Provide a single identifier for container - ID or name.")
|
|
369
538
|
raise typer.Exit(1)
|
|
370
539
|
|
|
371
540
|
service_factory = validate_config_and_get_service_factory()
|
|
@@ -377,7 +546,7 @@ def restart_container(
|
|
|
377
546
|
action=DockerContainerAction.RESTART
|
|
378
547
|
)
|
|
379
548
|
|
|
380
|
-
app_logger.info(f'Container
|
|
549
|
+
app_logger.info(f'Container is restarting')
|
|
381
550
|
raise typer.Exit(0)
|
|
382
551
|
|
|
383
552
|
|
|
@@ -410,7 +579,7 @@ def container_logs(
|
|
|
410
579
|
check_command_permission(command_name)
|
|
411
580
|
|
|
412
581
|
if sum(v is not None for v in [container_public_id, container_slug]) != 1:
|
|
413
|
-
typer.echo("
|
|
582
|
+
typer.echo("Provide a single identifier for container - ID or name.")
|
|
414
583
|
raise typer.Exit(1)
|
|
415
584
|
|
|
416
585
|
service_factory = validate_config_and_get_service_factory()
|
|
@@ -425,4 +594,4 @@ def container_logs(
|
|
|
425
594
|
logging_service.print_last_container_logs(container_public_id=container_public_id, container_slug=container_slug, logs_number=logs_number)
|
|
426
595
|
|
|
427
596
|
app_logger.info(f'Container log streaming completed')
|
|
428
|
-
raise typer.Exit(0)
|
|
597
|
+
raise typer.Exit(0)
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
from typing import Optional, List, Dict
|
|
2
2
|
|
|
3
3
|
from thestage.config.business.config_provider import ConfigProvider
|
|
4
|
+
from thestage.docker_container.dto.docker_container_create_request import DockerContainerCreateRequest
|
|
5
|
+
from thestage.docker_container.dto.docker_container_create_response import DockerContainerCreateResult
|
|
6
|
+
from thestage.docker_container.dto.docker_image_list_request import DockerImageListRequest
|
|
7
|
+
from thestage.docker_container.dto.docker_image_list_response import DockerImageListResponse
|
|
4
8
|
from thestage.global_dto.enums.order_direction_type import OrderDirectionType
|
|
5
9
|
from thestage.services.clients.thestage_api.core.api_client_core import TheStageApiClientCore
|
|
6
10
|
from thestage.services.clients.thestage_api.dtos.base_response import TheStageBaseResponse
|
|
@@ -11,7 +15,7 @@ from thestage.docker_container.dto.container_action_request import DockerContain
|
|
|
11
15
|
from thestage.docker_container.dto.container_response import (
|
|
12
16
|
DockerContainerDto,
|
|
13
17
|
DockerContainerViewResponse,
|
|
14
|
-
ContainerBusinessStatusMapperResponse
|
|
18
|
+
ContainerBusinessStatusMapperResponse, DockerImageDto
|
|
15
19
|
)
|
|
16
20
|
from thestage.docker_container.dto.docker_container_list_request import DockerContainerListRequest
|
|
17
21
|
from thestage.docker_container.dto.docker_container_list_response import DockerContainerListResponse
|
|
@@ -50,9 +54,32 @@ class DockerContainerApiClient(TheStageApiClientCore):
|
|
|
50
54
|
)
|
|
51
55
|
|
|
52
56
|
result = DockerContainerListResponse.model_validate(response) if response else None
|
|
53
|
-
# return result.paginatedList.entities, result.paginatedList.pagination_data.total_pages if result and result.is_success else None
|
|
54
57
|
return result.paginatedList if result and result.is_success else None
|
|
55
58
|
|
|
59
|
+
|
|
60
|
+
def get_docker_image_list(
|
|
61
|
+
self,
|
|
62
|
+
page: int = 1,
|
|
63
|
+
limit: int = 10,
|
|
64
|
+
) -> PaginatedEntityList[DockerImageDto]:
|
|
65
|
+
request = DockerImageListRequest(
|
|
66
|
+
entityFilterRequest=EntityFilterRequest(
|
|
67
|
+
orderByField="createdAt",
|
|
68
|
+
orderByDirection=OrderDirectionType.DESC,
|
|
69
|
+
page=page,
|
|
70
|
+
limit=limit,
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
response = self._request(
|
|
74
|
+
method='POST',
|
|
75
|
+
url='/user-api/v1/docker-image/list',
|
|
76
|
+
data=request.model_dump(),
|
|
77
|
+
token=self.__config_provider.get_config().main.thestage_auth_token
|
|
78
|
+
)
|
|
79
|
+
result = DockerImageListResponse.model_validate(response) if response else None
|
|
80
|
+
return result.paginatedList if result and result.is_success else None
|
|
81
|
+
|
|
82
|
+
|
|
56
83
|
def get_container(
|
|
57
84
|
self,
|
|
58
85
|
container_slug: Optional[str] = None,
|
|
@@ -72,6 +99,18 @@ class DockerContainerApiClient(TheStageApiClientCore):
|
|
|
72
99
|
|
|
73
100
|
return DockerContainerViewResponse.model_validate(response).docker_container if response else None
|
|
74
101
|
|
|
102
|
+
|
|
103
|
+
def create_container(self, request_param: DockerContainerCreateRequest) -> Optional[DockerContainerCreateResult]:
|
|
104
|
+
response = self._request(
|
|
105
|
+
method='POST',
|
|
106
|
+
url='/user-api/v1/docker-container/create',
|
|
107
|
+
data=request_param.model_dump(by_alias=True),
|
|
108
|
+
token=self.__config_provider.get_config().main.thestage_auth_token
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
return DockerContainerCreateResult.model_validate(response) if response else None
|
|
112
|
+
|
|
113
|
+
|
|
75
114
|
def container_action(
|
|
76
115
|
self,
|
|
77
116
|
request_param: DockerContainerActionRequest,
|
|
@@ -87,6 +126,7 @@ class DockerContainerApiClient(TheStageApiClientCore):
|
|
|
87
126
|
result = TheStageBaseResponse.model_validate(response) if response else None
|
|
88
127
|
return result
|
|
89
128
|
|
|
129
|
+
|
|
90
130
|
def get_container_business_status_map(self) -> Optional[Dict[str, str]]:
|
|
91
131
|
response = self._request(
|
|
92
132
|
method='POST',
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
|
|
3
|
+
from thestage.cli_command import CliCommand
|
|
4
|
+
from thestage.cli_command_helper import get_command_metadata, check_command_permission
|
|
5
|
+
from thestage.controllers.utils_controller import validate_config_and_get_service_factory
|
|
6
|
+
from thestage.docker_container.business.container_service import ContainerService
|
|
7
|
+
from thestage.i18n.translation import __
|
|
8
|
+
|
|
9
|
+
app = typer.Typer(no_args_is_help=True, help=__("Manage Docker images"))
|
|
10
|
+
|
|
11
|
+
@app.command(name='ls', help=__("List available docker images"), **get_command_metadata(CliCommand.CONTAINER_LS))
|
|
12
|
+
def list_available_images(
|
|
13
|
+
row: int = typer.Option(
|
|
14
|
+
5,
|
|
15
|
+
'--row',
|
|
16
|
+
'-r',
|
|
17
|
+
help=__("Set number of rows displayed per page"),
|
|
18
|
+
is_eager=False,
|
|
19
|
+
),
|
|
20
|
+
page: int = typer.Option(
|
|
21
|
+
1,
|
|
22
|
+
'--page',
|
|
23
|
+
'-p',
|
|
24
|
+
help=__("Set starting page for displaying output"),
|
|
25
|
+
is_eager=False,
|
|
26
|
+
),
|
|
27
|
+
):
|
|
28
|
+
command_name = CliCommand.CONTAINER_IMAGE_LS
|
|
29
|
+
check_command_permission(command_name)
|
|
30
|
+
|
|
31
|
+
service_factory = validate_config_and_get_service_factory()
|
|
32
|
+
container_service: ContainerService = service_factory.get_container_service()
|
|
33
|
+
|
|
34
|
+
container_service.print_docker_image_list(
|
|
35
|
+
row=row,
|
|
36
|
+
page=page,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
typer.echo(__("Images listing complete"))
|
|
40
|
+
raise typer.Exit(0)
|
|
@@ -45,3 +45,10 @@ class ContainerBusinessStatusMapperResponse(TheStageBasePaginatedResponse):
|
|
|
45
45
|
model_config = ConfigDict(use_enum_values=True)
|
|
46
46
|
|
|
47
47
|
docker_container_status_map: Dict[str, str] = Field(default={}, alias='dockerContainerStatusMap')
|
|
48
|
+
|
|
49
|
+
class DockerImageDto(BaseModel):
|
|
50
|
+
model_config = ConfigDict(use_enum_values=True)
|
|
51
|
+
|
|
52
|
+
id: Optional[int] = Field(None, alias='id')
|
|
53
|
+
image: Optional[str] = Field(None, alias='image')
|
|
54
|
+
tag: Optional[str] = Field(None, alias='tag')
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from typing import Optional, Dict
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field, ConfigDict
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DockerContainerMappings(BaseModel):
|
|
7
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
8
|
+
|
|
9
|
+
directory_mappings: Dict[str, str] = Field(default_factory=dict, alias='directoryMappings')
|
|
10
|
+
port_mappings: Dict[str, str] = Field(default_factory=dict, alias='portMappings')
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DockerContainerCreateRequest(BaseModel):
|
|
14
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
15
|
+
|
|
16
|
+
instance_rented_public_id: Optional[str] = Field(None, alias='instanceRentedPublicId')
|
|
17
|
+
instance_rented_slug: Optional[str] = Field(None, alias='instanceRentedSlug')
|
|
18
|
+
selfhosted_instance_public_id: Optional[str] = Field(None, alias='selfhostedInstancePublicId')
|
|
19
|
+
selfhosted_instance_slug: Optional[str] = Field(None, alias='selfhostedInstanceSlug')
|
|
20
|
+
project_public_id: Optional[str] = Field(..., alias='projectPublicId')
|
|
21
|
+
project_slug: Optional[str] = Field(..., alias='projectSlug')
|
|
22
|
+
container_slug: str = Field(..., alias='containerSlug')
|
|
23
|
+
docker_image_id: int = Field(..., alias='dockerImageId')
|
|
24
|
+
assigned_cpus: Optional[int] = Field(None, alias='assignedCpus')
|
|
25
|
+
is_unlimited_cpus: bool = Field(False, alias='isUnlimitedCpus')
|
|
26
|
+
assigned_gpus: Optional[int] = Field(None, alias='assignedGpus')
|
|
27
|
+
is_unlimited_gpus: bool = Field(False, alias='isUnlimitedGpus')
|
|
28
|
+
mappings: DockerContainerMappings = Field(default_factory=DockerContainerMappings, alias='mappings')
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import Field, ConfigDict
|
|
4
|
+
|
|
5
|
+
from thestage.services.clients.thestage_api.dtos.base_response import TheStageBaseResponse
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DockerContainerCreateResult(TheStageBaseResponse):
|
|
9
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
10
|
+
|
|
11
|
+
docker_container_public_id: Optional[str] = Field(None, alias='dockerContainerPublicId')
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from typing import Optional, List
|
|
2
|
+
|
|
3
|
+
from pydantic import Field, ConfigDict, BaseModel
|
|
4
|
+
|
|
5
|
+
from thestage.services.clients.thestage_api.dtos.entity_filter_request import EntityFilterRequest
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DockerImageListRequest(BaseModel):
|
|
9
|
+
model_config = ConfigDict(use_enum_values=True)
|
|
10
|
+
|
|
11
|
+
entityFilterRequest: EntityFilterRequest = Field(None, alias='entityFilterRequest')
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from typing import List, Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import Field, ConfigDict
|
|
4
|
+
|
|
5
|
+
from thestage.docker_container.dto.container_response import DockerImageDto
|
|
6
|
+
from thestage.services.clients.thestage_api.dtos.base_response import TheStageBaseResponse
|
|
7
|
+
from thestage.services.clients.thestage_api.dtos.paginated_entity_list import PaginatedEntityList
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DockerImageListResponse(TheStageBaseResponse):
|
|
11
|
+
model_config = ConfigDict(use_enum_values=True)
|
|
12
|
+
|
|
13
|
+
paginatedList: PaginatedEntityList[DockerImageDto] = Field(None, alias='paginatedList')
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DockerImageEntity(BaseModel):
|
|
7
|
+
|
|
8
|
+
model_config = ConfigDict(
|
|
9
|
+
populate_by_name=True,
|
|
10
|
+
use_enum_values=True,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
image: Optional[str] = Field(None, alias='IMAGE')
|
|
14
|
+
tag: Optional[str] = Field(None, alias='TAG')
|