thestage 0.5.471__py3-none-any.whl → 0.6.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- thestage/.env +5 -5
- thestage/__init__.py +3 -4
- thestage/__main__.py +9 -9
- thestage/cli_command.py +56 -56
- thestage/cli_command_helper.py +51 -51
- thestage/color_scheme/color_scheme.py +7 -7
- thestage/config/__init__.py +18 -18
- thestage/config/config_storage.py +5 -5
- thestage/config/env_base.py +7 -7
- thestage/controllers/__init__.py +0 -0
- thestage/controllers/base_controller.py +67 -67
- thestage/controllers/config_controller.py +137 -137
- thestage/controllers/container_controller.py +389 -389
- thestage/controllers/instance_controller.py +183 -183
- thestage/controllers/project_controller.py +802 -783
- thestage/controllers/utils_controller.py +32 -32
- thestage/debug_main.dist.py +28 -28
- thestage/entities/__init__.py +0 -0
- thestage/entities/container.py +17 -17
- thestage/entities/enums/__init__.py +0 -0
- thestage/entities/enums/order_direction_type.py +6 -6
- thestage/entities/enums/shell_type.py +7 -7
- thestage/entities/enums/tail_output_type.py +6 -6
- thestage/entities/enums/yes_no_response.py +7 -7
- thestage/entities/file_item.py +27 -27
- thestage/entities/project_inference_simulator.py +18 -18
- thestage/entities/project_inference_simulator_model.py +16 -16
- thestage/entities/project_task.py +19 -19
- thestage/entities/rented_instance.py +19 -19
- thestage/entities/self_hosted_instance.py +18 -18
- thestage/exceptions/__init__.py +0 -0
- thestage/exceptions/auth_exception.py +6 -6
- thestage/exceptions/base_exception.py +13 -13
- thestage/exceptions/business_logic_exception.py +6 -6
- thestage/exceptions/config_exception.py +6 -6
- thestage/exceptions/file_system_exception.py +6 -6
- thestage/exceptions/git_access_exception.py +17 -17
- thestage/exceptions/remote_server_exception.py +24 -24
- thestage/git/ProgressPrinter.py +22 -22
- thestage/helpers/__init__.py +0 -0
- thestage/helpers/error_handler.py +115 -115
- thestage/helpers/exception_hook.py +14 -14
- thestage/helpers/logger/__init__.py +0 -0
- thestage/helpers/logger/app_logger.py +50 -50
- thestage/helpers/ssh_util.py +38 -38
- thestage/i18n/en_GB/messages.po +947 -947
- thestage/i18n/translation.py +9 -9
- thestage/main.py +36 -36
- thestage/services/.env +6 -6
- thestage/services/__init__.py +0 -0
- thestage/services/abstract_mapper.py +9 -9
- thestage/services/abstract_service.py +87 -87
- thestage/services/app_config_service.py +52 -52
- thestage/services/clients/__init__.py +0 -0
- thestage/services/clients/git/__init__.py +0 -0
- thestage/services/clients/git/git_client.py +433 -331
- thestage/services/clients/thestage_api/__init__.py +0 -0
- thestage/services/clients/thestage_api/api_client.py +718 -720
- thestage/services/clients/thestage_api/core/api_client_core.py +108 -108
- thestage/services/clients/thestage_api/core/http_client_exception.py +12 -12
- thestage/services/clients/thestage_api/dtos/__init__.py +0 -0
- thestage/services/clients/thestage_api/dtos/base_response.py +13 -13
- thestage/services/clients/thestage_api/dtos/cloud_provider_region.py +19 -19
- thestage/services/clients/thestage_api/dtos/container_param_request.py +11 -11
- thestage/services/clients/thestage_api/dtos/container_response.py +67 -67
- thestage/services/clients/thestage_api/dtos/docker_container_assigned_device.py +10 -10
- thestage/services/clients/thestage_api/dtos/docker_container_controller/docker_container_list_request.py +13 -13
- thestage/services/clients/thestage_api/dtos/docker_container_controller/docker_container_list_response.py +13 -13
- thestage/services/clients/thestage_api/dtos/docker_container_mapping.py +10 -10
- thestage/services/clients/thestage_api/dtos/entity_filter_request.py +14 -14
- thestage/services/clients/thestage_api/dtos/enums/__init__.py +0 -0
- thestage/services/clients/thestage_api/dtos/enums/container_pending_action.py +10 -10
- thestage/services/clients/thestage_api/dtos/enums/container_status.py +17 -17
- thestage/services/clients/thestage_api/dtos/enums/cpu_type.py +8 -8
- thestage/services/clients/thestage_api/dtos/enums/currency_type.py +10 -10
- thestage/services/clients/thestage_api/dtos/enums/daemon_status.py +9 -9
- thestage/services/clients/thestage_api/dtos/enums/disk_type.py +7 -7
- thestage/services/clients/thestage_api/dtos/enums/drive_type.py +7 -7
- thestage/services/clients/thestage_api/dtos/enums/gpu_name.py +8 -8
- thestage/services/clients/thestage_api/dtos/enums/inference_model_status.py +9 -9
- thestage/services/clients/thestage_api/dtos/enums/inference_simulator_status.py +15 -15
- thestage/services/clients/thestage_api/dtos/enums/instance_rented_status.py +17 -17
- thestage/services/clients/thestage_api/dtos/enums/instance_type.py +7 -7
- thestage/services/clients/thestage_api/dtos/enums/location_region.py +11 -11
- thestage/services/clients/thestage_api/dtos/enums/power_status.py +10 -10
- thestage/services/clients/thestage_api/dtos/enums/provider_name.py +11 -11
- thestage/services/clients/thestage_api/dtos/enums/selfhosted_status.py +10 -10
- thestage/services/clients/thestage_api/dtos/enums/task_execution_status.py +12 -12
- thestage/services/clients/thestage_api/dtos/enums/task_status.py +12 -12
- thestage/services/clients/thestage_api/dtos/frontend_status.py +10 -10
- thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_instance_request.py +13 -13
- thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_instance_response.py +13 -13
- thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_sagemaker_request.py +12 -12
- thestage/services/clients/thestage_api/dtos/inference_controller/deploy_inference_model_to_sagemaker_response.py +12 -12
- thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_request.py +10 -10
- thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_response.py +13 -13
- thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_list_for_project_request.py +14 -14
- thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_list_for_project_response.py +12 -12
- thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_model_list_for_project_request.py +12 -12
- thestage/services/clients/thestage_api/dtos/inference_controller/inference_simulator_model_list_for_project_response.py +13 -13
- thestage/services/clients/thestage_api/dtos/inference_simulator_model_response.py +11 -11
- thestage/services/clients/thestage_api/dtos/inference_simulator_response.py +11 -11
- thestage/services/clients/thestage_api/dtos/installed_service.py +17 -17
- thestage/services/clients/thestage_api/dtos/instance_detected_gpus.py +20 -20
- thestage/services/clients/thestage_api/dtos/instance_rented_response.py +71 -71
- thestage/services/clients/thestage_api/dtos/logging_controller/docker_container_log_stream_request.py +7 -7
- thestage/services/clients/thestage_api/dtos/logging_controller/log_polling_request.py +13 -13
- thestage/services/clients/thestage_api/dtos/logging_controller/log_polling_response.py +14 -14
- thestage/services/clients/thestage_api/dtos/logging_controller/task_log_stream_request.py +7 -7
- thestage/services/clients/thestage_api/dtos/logging_controller/user_logs_query_request.py +21 -21
- thestage/services/clients/thestage_api/dtos/logging_controller/user_logs_query_response.py +14 -14
- thestage/services/clients/thestage_api/dtos/paginated_entity_list.py +11 -11
- thestage/services/clients/thestage_api/dtos/pagination_data.py +10 -10
- thestage/services/clients/thestage_api/dtos/price_definition.py +14 -14
- thestage/services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_request.py +7 -7
- thestage/services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_response.py +10 -10
- thestage/services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_request.py +8 -8
- thestage/services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_response.py +6 -6
- thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_request.py +15 -15
- thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_response.py +10 -10
- thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_request.py +13 -14
- thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_response.py +10 -10
- thestage/services/clients/thestage_api/dtos/project_response.py +32 -32
- thestage/services/clients/thestage_api/dtos/selfhosted_instance_response.py +56 -56
- thestage/services/clients/thestage_api/dtos/sftp_path_helper.py +13 -13
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_key_to_user_request.py +8 -8
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_key_to_user_response.py +11 -11
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_public_key_to_instance_request.py +8 -8
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/add_ssh_public_key_to_instance_response.py +11 -11
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/is_user_has_public_ssh_key_request.py +7 -7
- thestage/services/clients/thestage_api/dtos/ssh_key_controller/is_user_has_public_ssh_key_response.py +12 -12
- thestage/services/clients/thestage_api/dtos/task_controller/task_list_for_project_request.py +10 -10
- thestage/services/clients/thestage_api/dtos/task_controller/task_list_for_project_response.py +12 -12
- thestage/services/clients/thestage_api/dtos/task_controller/task_status_localized_map_response.py +9 -9
- thestage/services/clients/thestage_api/dtos/task_controller/task_view_response.py +12 -12
- thestage/services/clients/thestage_api/dtos/user_controller/user_profile.py +12 -12
- thestage/services/clients/thestage_api/dtos/validate_token_response.py +11 -11
- thestage/services/config_provider/__init__.py +0 -0
- thestage/services/config_provider/config_provider.py +237 -237
- thestage/services/connect/connect_service.py +196 -196
- thestage/services/connect/dto/remote_server_config.py +9 -9
- thestage/services/container/__init__.py +0 -0
- thestage/services/container/container_service.py +374 -374
- thestage/services/container/mapper/__init__.py +0 -0
- thestage/services/container/mapper/container_mapper.py +30 -30
- thestage/services/core_files/config_entity.py +26 -26
- thestage/services/filesystem_service.py +133 -133
- thestage/services/instance/__init__.py +0 -0
- thestage/services/instance/instance_service.py +303 -303
- thestage/services/instance/mapper/__init__.py +0 -0
- thestage/services/instance/mapper/instance_mapper.py +24 -24
- thestage/services/instance/mapper/selfhosted_mapper.py +33 -33
- thestage/services/logging/byte_print_style.py +5 -5
- thestage/services/logging/dto/log_message.py +15 -15
- thestage/services/logging/dto/log_type.py +6 -6
- thestage/services/logging/exception/log_polling_exception.py +6 -6
- thestage/services/logging/logging_constants.py +3 -3
- thestage/services/logging/logging_service.py +367 -367
- thestage/services/project/__init__.py +0 -0
- thestage/services/project/dto/inference_simulator_dto.py +22 -22
- thestage/services/project/dto/inference_simulator_model_dto.py +20 -20
- thestage/services/project/dto/project_config.py +14 -14
- thestage/services/project/mapper/__init__.py +0 -0
- thestage/services/project/mapper/project_inference_simulator_mapper.py +21 -21
- thestage/services/project/mapper/project_inference_simulator_model_mapper.py +21 -21
- thestage/services/project/mapper/project_task_mapper.py +22 -22
- thestage/services/project/project_service.py +1260 -1241
- thestage/services/remote_server_service.py +609 -609
- thestage/services/service_factory.py +97 -97
- thestage/services/task/dto/task_dto.py +40 -40
- thestage/services/validation_service.py +61 -61
- {thestage-0.5.471.dist-info → thestage-0.6.1.dist-info}/LICENSE.txt +12 -12
- {thestage-0.5.471.dist-info → thestage-0.6.1.dist-info}/METADATA +1 -1
- thestage-0.6.1.dist-info/RECORD +176 -0
- {thestage-0.5.471.dist-info → thestage-0.6.1.dist-info}/WHEEL +1 -1
- thestage/debug_tests.py +0 -12
- thestage/services/clients/.DS_Store +0 -0
- thestage-0.5.471.dist-info/RECORD +0 -178
- {thestage-0.5.471.dist-info → thestage-0.6.1.dist-info}/entry_points.txt +0 -0
thestage/git/ProgressPrinter.py
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
from git import RemoteProgress
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class ProgressPrinter(RemoteProgress):
|
|
5
|
-
def __init__( self ):
|
|
6
|
-
super().__init__()
|
|
7
|
-
|
|
8
|
-
self.__all_dropped_lines = []
|
|
9
|
-
|
|
10
|
-
def update( self, op_code, cur_count, max_count=None, message='' ):
|
|
11
|
-
pass
|
|
12
|
-
|
|
13
|
-
def line_dropped( self, line ):
|
|
14
|
-
if line.startswith( 'POST git-upload-pack' ):
|
|
15
|
-
return
|
|
16
|
-
|
|
17
|
-
self.__all_dropped_lines.append( line )
|
|
18
|
-
|
|
19
|
-
def allErrorLines( self ):
|
|
20
|
-
return self.error_lines + self.__all_dropped_lines
|
|
21
|
-
|
|
22
|
-
def allDroppedLines( self ):
|
|
1
|
+
from git import RemoteProgress
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ProgressPrinter(RemoteProgress):
|
|
5
|
+
def __init__( self ):
|
|
6
|
+
super().__init__()
|
|
7
|
+
|
|
8
|
+
self.__all_dropped_lines = []
|
|
9
|
+
|
|
10
|
+
def update( self, op_code, cur_count, max_count=None, message='' ):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
def line_dropped( self, line ):
|
|
14
|
+
if line.startswith( 'POST git-upload-pack' ):
|
|
15
|
+
return
|
|
16
|
+
|
|
17
|
+
self.__all_dropped_lines.append( line )
|
|
18
|
+
|
|
19
|
+
def allErrorLines( self ):
|
|
20
|
+
return self.error_lines + self.__all_dropped_lines
|
|
21
|
+
|
|
22
|
+
def allDroppedLines( self ):
|
|
23
23
|
return self.__all_dropped_lines
|
thestage/helpers/__init__.py
CHANGED
|
File without changes
|
|
@@ -1,115 +1,115 @@
|
|
|
1
|
-
import traceback
|
|
2
|
-
from typing import Any, Callable
|
|
3
|
-
|
|
4
|
-
import requests
|
|
5
|
-
import typer
|
|
6
|
-
from click.exceptions import Exit, Abort
|
|
7
|
-
from git import GitCommandError
|
|
8
|
-
from paramiko.ssh_exception import PasswordRequiredException
|
|
9
|
-
|
|
10
|
-
from thestage.config import THESTAGE_API_URL
|
|
11
|
-
from thestage.exceptions.file_system_exception import FileSystemException
|
|
12
|
-
from thestage.exceptions.remote_server_exception import RemoteServerException
|
|
13
|
-
from thestage.i18n.translation import __
|
|
14
|
-
from thestage.exceptions.git_access_exception import GitAccessException
|
|
15
|
-
from thestage.exceptions.auth_exception import AuthException
|
|
16
|
-
from thestage.exceptions.business_logic_exception import BusinessLogicException
|
|
17
|
-
from thestage.exceptions.config_exception import ConfigException
|
|
18
|
-
from thestage.helpers.logger.app_logger import app_logger
|
|
19
|
-
from thestage.services.clients.thestage_api.core.http_client_exception import HttpClientException
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def error_handler() -> Callable:
|
|
23
|
-
def wrap(f):
|
|
24
|
-
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
25
|
-
try:
|
|
26
|
-
result = f(*args, **kwargs)
|
|
27
|
-
return result
|
|
28
|
-
except AuthException as e1:
|
|
29
|
-
typer.echo(__('Authentication failed: update API token'))
|
|
30
|
-
app_logger.error(f'{traceback.format_exc()}')
|
|
31
|
-
raise typer.Exit(1)
|
|
32
|
-
except BusinessLogicException as e2:
|
|
33
|
-
typer.echo(__('Business logic error encountered: contact TheStage AI team'))
|
|
34
|
-
app_logger.error(f'{traceback.format_exc()}')
|
|
35
|
-
raise typer.Exit(1)
|
|
36
|
-
except ConfigException as e3:
|
|
37
|
-
typer.echo(__(
|
|
38
|
-
'Configuration error encountered: %error_message%',
|
|
39
|
-
{
|
|
40
|
-
'error_message': e3.get_message()
|
|
41
|
-
}
|
|
42
|
-
))
|
|
43
|
-
app_logger.error(f'{traceback.format_exc()}')
|
|
44
|
-
raise typer.Exit(1)
|
|
45
|
-
except FileSystemException as e4:
|
|
46
|
-
typer.echo(__(
|
|
47
|
-
"File system error encountered: %error_message%",
|
|
48
|
-
{
|
|
49
|
-
'error_message': e4.get_message()
|
|
50
|
-
}
|
|
51
|
-
))
|
|
52
|
-
app_logger.error(f'{traceback.format_exc()}')
|
|
53
|
-
raise typer.Exit(1)
|
|
54
|
-
except HttpClientException as e5:
|
|
55
|
-
typer.echo(__(
|
|
56
|
-
f"TheStage server error: %error_message%",
|
|
57
|
-
|
|
58
|
-
{
|
|
59
|
-
'stage_url': THESTAGE_API_URL,
|
|
60
|
-
'error_message': e5.get_message()
|
|
61
|
-
}
|
|
62
|
-
))
|
|
63
|
-
app_logger.error(f"Connection error to {THESTAGE_API_URL} - {e5}")
|
|
64
|
-
app_logger.error(f'{traceback.format_exc()}')
|
|
65
|
-
raise typer.Exit(1)
|
|
66
|
-
except GitAccessException as e6:
|
|
67
|
-
typer.echo(e6.get_message())
|
|
68
|
-
typer.echo(e6.get_dop_message())
|
|
69
|
-
typer.echo(__(
|
|
70
|
-
"Visit %git_url% to accept the invitation or check your access to the repository",
|
|
71
|
-
{
|
|
72
|
-
'git_url': e6.get_url(),
|
|
73
|
-
}
|
|
74
|
-
))
|
|
75
|
-
app_logger.error(f'{traceback.format_exc()}')
|
|
76
|
-
raise typer.Exit(1)
|
|
77
|
-
except GitCommandError as e7:
|
|
78
|
-
typer.echo(f'Git command error encountered: {e7.stderr} (status: {e7.status})')
|
|
79
|
-
app_logger.error(f'{traceback.format_exc()}')
|
|
80
|
-
raise typer.Exit(1)
|
|
81
|
-
except RemoteServerException as e8:
|
|
82
|
-
typer.echo(__(
|
|
83
|
-
'Error connecting to server or Docker container at %ip_address% as %username%',
|
|
84
|
-
{
|
|
85
|
-
'ip_address': e8.ip_address,
|
|
86
|
-
'username': e8.username,
|
|
87
|
-
}))
|
|
88
|
-
app_logger.error(f'Error connecting to server or Docker container at {e8.ip_address} as {e8.username} - {e8}')
|
|
89
|
-
app_logger.error(f'{traceback.format_exc()}')
|
|
90
|
-
raise typer.Exit(1)
|
|
91
|
-
except Abort as e9:
|
|
92
|
-
app_logger.error(f'{traceback.format_exc()}')
|
|
93
|
-
raise typer.Exit(1)
|
|
94
|
-
except requests.exceptions.ConnectionError as e10:
|
|
95
|
-
# TODO we don't know for sure if it is Thestage connection error - throw appropriate exception (on token validation?)
|
|
96
|
-
typer.echo("Connection error")
|
|
97
|
-
app_logger.error(f'{traceback.format_exc()}')
|
|
98
|
-
raise typer.Exit(1)
|
|
99
|
-
except PasswordRequiredException as e11:
|
|
100
|
-
# technically we can use encrypted keys but dealing with passwords is big bs
|
|
101
|
-
typer.echo("Provided key requires password. Please use non-encrypted key.")
|
|
102
|
-
app_logger.error(f'{traceback.format_exc()}')
|
|
103
|
-
raise typer.Exit(1)
|
|
104
|
-
except Exception as e100:
|
|
105
|
-
if isinstance(e100, Exit):
|
|
106
|
-
raise e100
|
|
107
|
-
else:
|
|
108
|
-
typer.echo(__('Undefined error occurred'))
|
|
109
|
-
# typer.echo(e100.__class__.__name__)
|
|
110
|
-
# print(traceback.format_exc())
|
|
111
|
-
# TODO send all exceptions to backend?
|
|
112
|
-
app_logger.error(f'{traceback.format_exc()}')
|
|
113
|
-
raise typer.Exit(1)
|
|
114
|
-
return wrapper
|
|
115
|
-
return wrap
|
|
1
|
+
import traceback
|
|
2
|
+
from typing import Any, Callable
|
|
3
|
+
|
|
4
|
+
import requests
|
|
5
|
+
import typer
|
|
6
|
+
from click.exceptions import Exit, Abort
|
|
7
|
+
from git import GitCommandError
|
|
8
|
+
from paramiko.ssh_exception import PasswordRequiredException
|
|
9
|
+
|
|
10
|
+
from thestage.config import THESTAGE_API_URL
|
|
11
|
+
from thestage.exceptions.file_system_exception import FileSystemException
|
|
12
|
+
from thestage.exceptions.remote_server_exception import RemoteServerException
|
|
13
|
+
from thestage.i18n.translation import __
|
|
14
|
+
from thestage.exceptions.git_access_exception import GitAccessException
|
|
15
|
+
from thestage.exceptions.auth_exception import AuthException
|
|
16
|
+
from thestage.exceptions.business_logic_exception import BusinessLogicException
|
|
17
|
+
from thestage.exceptions.config_exception import ConfigException
|
|
18
|
+
from thestage.helpers.logger.app_logger import app_logger
|
|
19
|
+
from thestage.services.clients.thestage_api.core.http_client_exception import HttpClientException
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def error_handler() -> Callable:
|
|
23
|
+
def wrap(f):
|
|
24
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
25
|
+
try:
|
|
26
|
+
result = f(*args, **kwargs)
|
|
27
|
+
return result
|
|
28
|
+
except AuthException as e1:
|
|
29
|
+
typer.echo(__('Authentication failed: update API token'))
|
|
30
|
+
app_logger.error(f'{traceback.format_exc()}')
|
|
31
|
+
raise typer.Exit(1)
|
|
32
|
+
except BusinessLogicException as e2:
|
|
33
|
+
typer.echo(__('Business logic error encountered: contact TheStage AI team'))
|
|
34
|
+
app_logger.error(f'{traceback.format_exc()}')
|
|
35
|
+
raise typer.Exit(1)
|
|
36
|
+
except ConfigException as e3:
|
|
37
|
+
typer.echo(__(
|
|
38
|
+
'Configuration error encountered: %error_message%',
|
|
39
|
+
{
|
|
40
|
+
'error_message': e3.get_message()
|
|
41
|
+
}
|
|
42
|
+
))
|
|
43
|
+
app_logger.error(f'{traceback.format_exc()}')
|
|
44
|
+
raise typer.Exit(1)
|
|
45
|
+
except FileSystemException as e4:
|
|
46
|
+
typer.echo(__(
|
|
47
|
+
"File system error encountered: %error_message%",
|
|
48
|
+
{
|
|
49
|
+
'error_message': e4.get_message()
|
|
50
|
+
}
|
|
51
|
+
))
|
|
52
|
+
app_logger.error(f'{traceback.format_exc()}')
|
|
53
|
+
raise typer.Exit(1)
|
|
54
|
+
except HttpClientException as e5:
|
|
55
|
+
typer.echo(__(
|
|
56
|
+
f"TheStage server error: %error_message%",
|
|
57
|
+
|
|
58
|
+
{
|
|
59
|
+
'stage_url': THESTAGE_API_URL,
|
|
60
|
+
'error_message': e5.get_message()
|
|
61
|
+
}
|
|
62
|
+
))
|
|
63
|
+
app_logger.error(f"Connection error to {THESTAGE_API_URL} - {e5}")
|
|
64
|
+
app_logger.error(f'{traceback.format_exc()}')
|
|
65
|
+
raise typer.Exit(1)
|
|
66
|
+
except GitAccessException as e6:
|
|
67
|
+
typer.echo(e6.get_message())
|
|
68
|
+
typer.echo(e6.get_dop_message())
|
|
69
|
+
typer.echo(__(
|
|
70
|
+
"Visit %git_url% to accept the invitation or check your access to the repository",
|
|
71
|
+
{
|
|
72
|
+
'git_url': e6.get_url(),
|
|
73
|
+
}
|
|
74
|
+
))
|
|
75
|
+
app_logger.error(f'{traceback.format_exc()}')
|
|
76
|
+
raise typer.Exit(1)
|
|
77
|
+
except GitCommandError as e7:
|
|
78
|
+
typer.echo(f'Git command error encountered: {e7.stderr} (status: {e7.status})')
|
|
79
|
+
app_logger.error(f'{traceback.format_exc()}')
|
|
80
|
+
raise typer.Exit(1)
|
|
81
|
+
except RemoteServerException as e8:
|
|
82
|
+
typer.echo(__(
|
|
83
|
+
'Error connecting to server or Docker container at %ip_address% as %username%',
|
|
84
|
+
{
|
|
85
|
+
'ip_address': e8.ip_address,
|
|
86
|
+
'username': e8.username,
|
|
87
|
+
}))
|
|
88
|
+
app_logger.error(f'Error connecting to server or Docker container at {e8.ip_address} as {e8.username} - {e8}')
|
|
89
|
+
app_logger.error(f'{traceback.format_exc()}')
|
|
90
|
+
raise typer.Exit(1)
|
|
91
|
+
except Abort as e9:
|
|
92
|
+
app_logger.error(f'{traceback.format_exc()}')
|
|
93
|
+
raise typer.Exit(1)
|
|
94
|
+
except requests.exceptions.ConnectionError as e10:
|
|
95
|
+
# TODO we don't know for sure if it is Thestage connection error - throw appropriate exception (on token validation?)
|
|
96
|
+
typer.echo("Connection error")
|
|
97
|
+
app_logger.error(f'{traceback.format_exc()}')
|
|
98
|
+
raise typer.Exit(1)
|
|
99
|
+
except PasswordRequiredException as e11:
|
|
100
|
+
# technically we can use encrypted keys but dealing with passwords is big bs
|
|
101
|
+
typer.echo("Provided key requires password. Please use non-encrypted key.")
|
|
102
|
+
app_logger.error(f'{traceback.format_exc()}')
|
|
103
|
+
raise typer.Exit(1)
|
|
104
|
+
except Exception as e100:
|
|
105
|
+
if isinstance(e100, Exit):
|
|
106
|
+
raise e100
|
|
107
|
+
else:
|
|
108
|
+
typer.echo(__('Undefined error occurred'))
|
|
109
|
+
# typer.echo(e100.__class__.__name__)
|
|
110
|
+
# print(traceback.format_exc())
|
|
111
|
+
# TODO send all exceptions to backend?
|
|
112
|
+
app_logger.error(f'{traceback.format_exc()}')
|
|
113
|
+
raise typer.Exit(1)
|
|
114
|
+
return wrapper
|
|
115
|
+
return wrap
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
import traceback
|
|
3
|
-
|
|
4
|
-
from thestage.helpers.logger.app_logger import app_logger
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def exception_handler(exception_type, exception, tb):
|
|
8
|
-
print(exception)
|
|
9
|
-
tb_list = traceback.format_exception(exception_type, exception, tb)
|
|
10
|
-
tb_text = ''.join(tb_list)
|
|
11
|
-
app_logger.error(tb_text)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
sys.excepthook = exception_handler
|
|
1
|
+
import sys
|
|
2
|
+
import traceback
|
|
3
|
+
|
|
4
|
+
from thestage.helpers.logger.app_logger import app_logger
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def exception_handler(exception_type, exception, tb):
|
|
8
|
+
print(exception)
|
|
9
|
+
tb_list = traceback.format_exception(exception_type, exception, tb)
|
|
10
|
+
tb_text = ''.join(tb_list)
|
|
11
|
+
app_logger.error(tb_text)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
sys.excepthook = exception_handler
|
|
File without changes
|
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import platform
|
|
3
|
-
from logging.handlers import RotatingFileHandler
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from thestage import __app_name__, __version__
|
|
6
|
-
|
|
7
|
-
from thestage.config import THESTAGE_CONFIG_DIR
|
|
8
|
-
|
|
9
|
-
from thestage.config import THESTAGE_LOGGING_FILE
|
|
10
|
-
from thestage.exceptions.file_system_exception import FileSystemException
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def get_log_path_from_os() -> Path:
|
|
14
|
-
system = platform.system()
|
|
15
|
-
if system == 'Linux':
|
|
16
|
-
path = Path.home().joinpath(THESTAGE_CONFIG_DIR).joinpath('logs')
|
|
17
|
-
elif system == 'Windows':
|
|
18
|
-
path = Path.home().joinpath(THESTAGE_CONFIG_DIR).joinpath('logs')
|
|
19
|
-
elif system == 'Darwin':
|
|
20
|
-
path = Path.home().joinpath('library').joinpath('logs').joinpath('thestage')
|
|
21
|
-
else:
|
|
22
|
-
path = Path.home().joinpath(THESTAGE_CONFIG_DIR).joinpath('logs')
|
|
23
|
-
|
|
24
|
-
if not path.exists():
|
|
25
|
-
try:
|
|
26
|
-
path.mkdir(exist_ok=True, parents=True)
|
|
27
|
-
except OSError:
|
|
28
|
-
raise FileSystemException("Error create log dir")
|
|
29
|
-
|
|
30
|
-
return path
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def build_logger(level) -> logging.Logger:
|
|
34
|
-
logger = logging.getLogger(f"{__app_name__} v{__version__}")
|
|
35
|
-
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
36
|
-
logger.setLevel(level)
|
|
37
|
-
|
|
38
|
-
log_path = get_log_path_from_os()
|
|
39
|
-
tsr_log_file = log_path.joinpath(THESTAGE_LOGGING_FILE)
|
|
40
|
-
|
|
41
|
-
if tsr_log_file:
|
|
42
|
-
file_h = RotatingFileHandler(filename=tsr_log_file, maxBytes=1024 * 10, backupCount=5)
|
|
43
|
-
file_h.setLevel(level)
|
|
44
|
-
file_h.setFormatter(formatter)
|
|
45
|
-
logger.addHandler(file_h)
|
|
46
|
-
|
|
47
|
-
return logger
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
app_logger = build_logger(level=logging.DEBUG)
|
|
1
|
+
import logging
|
|
2
|
+
import platform
|
|
3
|
+
from logging.handlers import RotatingFileHandler
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from thestage import __app_name__, __version__
|
|
6
|
+
|
|
7
|
+
from thestage.config import THESTAGE_CONFIG_DIR
|
|
8
|
+
|
|
9
|
+
from thestage.config import THESTAGE_LOGGING_FILE
|
|
10
|
+
from thestage.exceptions.file_system_exception import FileSystemException
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_log_path_from_os() -> Path:
|
|
14
|
+
system = platform.system()
|
|
15
|
+
if system == 'Linux':
|
|
16
|
+
path = Path.home().joinpath(THESTAGE_CONFIG_DIR).joinpath('logs')
|
|
17
|
+
elif system == 'Windows':
|
|
18
|
+
path = Path.home().joinpath(THESTAGE_CONFIG_DIR).joinpath('logs')
|
|
19
|
+
elif system == 'Darwin':
|
|
20
|
+
path = Path.home().joinpath('library').joinpath('logs').joinpath('thestage')
|
|
21
|
+
else:
|
|
22
|
+
path = Path.home().joinpath(THESTAGE_CONFIG_DIR).joinpath('logs')
|
|
23
|
+
|
|
24
|
+
if not path.exists():
|
|
25
|
+
try:
|
|
26
|
+
path.mkdir(exist_ok=True, parents=True)
|
|
27
|
+
except OSError:
|
|
28
|
+
raise FileSystemException("Error create log dir")
|
|
29
|
+
|
|
30
|
+
return path
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def build_logger(level) -> logging.Logger:
|
|
34
|
+
logger = logging.getLogger(f"{__app_name__} v{__version__}")
|
|
35
|
+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
36
|
+
logger.setLevel(level)
|
|
37
|
+
|
|
38
|
+
log_path = get_log_path_from_os()
|
|
39
|
+
tsr_log_file = log_path.joinpath(THESTAGE_LOGGING_FILE)
|
|
40
|
+
|
|
41
|
+
if tsr_log_file:
|
|
42
|
+
file_h = RotatingFileHandler(filename=tsr_log_file, maxBytes=1024 * 10, backupCount=5)
|
|
43
|
+
file_h.setLevel(level)
|
|
44
|
+
file_h.setFormatter(formatter)
|
|
45
|
+
logger.addHandler(file_h)
|
|
46
|
+
|
|
47
|
+
return logger
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
app_logger = build_logger(level=logging.DEBUG)
|
thestage/helpers/ssh_util.py
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
from typing import Optional, List
|
|
2
|
-
|
|
3
|
-
import typer
|
|
4
|
-
from paramiko.dsskey import DSSKey
|
|
5
|
-
from paramiko.ecdsakey import ECDSAKey
|
|
6
|
-
from paramiko.ed25519key import Ed25519Key
|
|
7
|
-
from paramiko.pkey import PKey
|
|
8
|
-
from paramiko.rsakey import RSAKey
|
|
9
|
-
from paramiko.ssh_exception import SSHException, PasswordRequiredException
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def parse_private_key(filename: str) -> Optional[PKey]:
|
|
13
|
-
error_output: List[str] = []
|
|
14
|
-
pkey: Optional[PKey] = None
|
|
15
|
-
pkey_class: Optional[str] = None
|
|
16
|
-
|
|
17
|
-
for pkey_class_item in (RSAKey, ECDSAKey, DSSKey, Ed25519Key):
|
|
18
|
-
try:
|
|
19
|
-
key = pkey_class_item.from_private_key_file(filename=filename)
|
|
20
|
-
pkey = key
|
|
21
|
-
pkey_class = pkey_class_item.__name__
|
|
22
|
-
break
|
|
23
|
-
except PasswordRequiredException as e1:
|
|
24
|
-
raise e1
|
|
25
|
-
except SSHException as e2:
|
|
26
|
-
error_output.append(f'[{pkey_class_item.__name__}]: {str(e2)}')
|
|
27
|
-
except Exception as e3:
|
|
28
|
-
error_output.append(f'[{pkey_class_item.__name__}]: Unexpected error: {e3.__class__.__name__}: {str(e3)}')
|
|
29
|
-
|
|
30
|
-
if pkey is None:
|
|
31
|
-
for line in error_output:
|
|
32
|
-
typer.echo(line)
|
|
33
|
-
|
|
34
|
-
if pkey_class and pkey_class == 'DSSKey':
|
|
35
|
-
typer.echo('DSA keys are not supported')
|
|
36
|
-
return None
|
|
37
|
-
|
|
38
|
-
return pkey
|
|
1
|
+
from typing import Optional, List
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from paramiko.dsskey import DSSKey
|
|
5
|
+
from paramiko.ecdsakey import ECDSAKey
|
|
6
|
+
from paramiko.ed25519key import Ed25519Key
|
|
7
|
+
from paramiko.pkey import PKey
|
|
8
|
+
from paramiko.rsakey import RSAKey
|
|
9
|
+
from paramiko.ssh_exception import SSHException, PasswordRequiredException
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def parse_private_key(filename: str) -> Optional[PKey]:
|
|
13
|
+
error_output: List[str] = []
|
|
14
|
+
pkey: Optional[PKey] = None
|
|
15
|
+
pkey_class: Optional[str] = None
|
|
16
|
+
|
|
17
|
+
for pkey_class_item in (RSAKey, ECDSAKey, DSSKey, Ed25519Key):
|
|
18
|
+
try:
|
|
19
|
+
key = pkey_class_item.from_private_key_file(filename=filename)
|
|
20
|
+
pkey = key
|
|
21
|
+
pkey_class = pkey_class_item.__name__
|
|
22
|
+
break
|
|
23
|
+
except PasswordRequiredException as e1:
|
|
24
|
+
raise e1
|
|
25
|
+
except SSHException as e2:
|
|
26
|
+
error_output.append(f'[{pkey_class_item.__name__}]: {str(e2)}')
|
|
27
|
+
except Exception as e3:
|
|
28
|
+
error_output.append(f'[{pkey_class_item.__name__}]: Unexpected error: {e3.__class__.__name__}: {str(e3)}')
|
|
29
|
+
|
|
30
|
+
if pkey is None:
|
|
31
|
+
for line in error_output:
|
|
32
|
+
typer.echo(line)
|
|
33
|
+
|
|
34
|
+
if pkey_class and pkey_class == 'DSSKey':
|
|
35
|
+
typer.echo('DSA keys are not supported')
|
|
36
|
+
return None
|
|
37
|
+
|
|
38
|
+
return pkey
|