qwak-sdk 0.5.102__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.
- qwak_sdk/__init__.py +9 -0
- qwak_sdk/cli.py +79 -0
- qwak_sdk/commands/__init__.py +0 -0
- qwak_sdk/commands/_logic/__init__.py +0 -0
- qwak_sdk/commands/_logic/tools.py +6 -0
- qwak_sdk/commands/admin/__init__.py +0 -0
- qwak_sdk/commands/admin/admin_commands_group.py +17 -0
- qwak_sdk/commands/admin/apikeys/__init__.py +0 -0
- qwak_sdk/commands/admin/apikeys/api_keys_commands_group.py +17 -0
- qwak_sdk/commands/admin/apikeys/generate/__init__.py +0 -0
- qwak_sdk/commands/admin/apikeys/generate/_logic.py +21 -0
- qwak_sdk/commands/admin/apikeys/generate/ui.py +45 -0
- qwak_sdk/commands/admin/apikeys/revoke/__init__.py +0 -0
- qwak_sdk/commands/admin/apikeys/revoke/_logic.py +22 -0
- qwak_sdk/commands/admin/apikeys/revoke/ui.py +31 -0
- qwak_sdk/commands/alerts/__init__.py +0 -0
- qwak_sdk/commands/alerts/alerts_commnad_group.py +18 -0
- qwak_sdk/commands/alerts/delete/__init__.py +0 -0
- qwak_sdk/commands/alerts/delete/_logic.py +5 -0
- qwak_sdk/commands/alerts/delete/ui.py +10 -0
- qwak_sdk/commands/alerts/list/__init__.py +0 -0
- qwak_sdk/commands/alerts/list/_logic.py +23 -0
- qwak_sdk/commands/alerts/list/ui.py +17 -0
- qwak_sdk/commands/alerts/register/__init__.py +0 -0
- qwak_sdk/commands/alerts/register/_logic.py +72 -0
- qwak_sdk/commands/alerts/register/ui.py +30 -0
- qwak_sdk/commands/audience/__init__.py +0 -0
- qwak_sdk/commands/audience/_logic/__init__.py +0 -0
- qwak_sdk/commands/audience/_logic/config/__init__.py +0 -0
- qwak_sdk/commands/audience/_logic/config/config_base.py +15 -0
- qwak_sdk/commands/audience/_logic/config/parser.py +30 -0
- qwak_sdk/commands/audience/_logic/config/v1/__init__.py +0 -0
- qwak_sdk/commands/audience/_logic/config/v1/audience_config.py +26 -0
- qwak_sdk/commands/audience/_logic/config/v1/conditions_config.py +59 -0
- qwak_sdk/commands/audience/_logic/config/v1/config_v1.py +23 -0
- qwak_sdk/commands/audience/_logic/config/v1/route_config.py +15 -0
- qwak_sdk/commands/audience/_logic/config/v1/spec.py +9 -0
- qwak_sdk/commands/audience/audience_api_dump.py +86 -0
- qwak_sdk/commands/audience/audience_commands_group.py +30 -0
- qwak_sdk/commands/audience/create/__init__.py +0 -0
- qwak_sdk/commands/audience/create/logic.py +41 -0
- qwak_sdk/commands/audience/create/ui.py +21 -0
- qwak_sdk/commands/audience/delete/__init__.py +0 -0
- qwak_sdk/commands/audience/delete/logic.py +13 -0
- qwak_sdk/commands/audience/delete/ui.py +17 -0
- qwak_sdk/commands/audience/get/__init__.py +0 -0
- qwak_sdk/commands/audience/get/logic.py +14 -0
- qwak_sdk/commands/audience/get/ui.py +25 -0
- qwak_sdk/commands/audience/list/__init__.py +0 -0
- qwak_sdk/commands/audience/list/logic.py +16 -0
- qwak_sdk/commands/audience/list/ui.py +26 -0
- qwak_sdk/commands/audience/update/__init__.py +0 -0
- qwak_sdk/commands/audience/update/logic.py +37 -0
- qwak_sdk/commands/audience/update/ui.py +26 -0
- qwak_sdk/commands/auto_scalling/__init__.py +0 -0
- qwak_sdk/commands/auto_scalling/_logic/__init__.py +0 -0
- qwak_sdk/commands/auto_scalling/_logic/config/__init__.py +3 -0
- qwak_sdk/commands/auto_scalling/_logic/config/config.py +152 -0
- qwak_sdk/commands/auto_scalling/_logic/config/parser.py +21 -0
- qwak_sdk/commands/auto_scalling/attach/__init__.py +0 -0
- qwak_sdk/commands/auto_scalling/attach/_logic.py +43 -0
- qwak_sdk/commands/auto_scalling/attach/ui.py +21 -0
- qwak_sdk/commands/auto_scalling/autoscaling_commands_group.py +15 -0
- qwak_sdk/commands/automations/__init__.py +0 -0
- qwak_sdk/commands/automations/automations_commands_group.py +30 -0
- qwak_sdk/commands/automations/delete/__init__.py +0 -0
- qwak_sdk/commands/automations/delete/_logic.py +6 -0
- qwak_sdk/commands/automations/delete/ui.py +23 -0
- qwak_sdk/commands/automations/executions/__init__.py +0 -0
- qwak_sdk/commands/automations/executions/executions_commands_group.py +14 -0
- qwak_sdk/commands/automations/executions/list/__init__.py +0 -0
- qwak_sdk/commands/automations/executions/list/_logic.py +8 -0
- qwak_sdk/commands/automations/executions/list/ui.py +25 -0
- qwak_sdk/commands/automations/list/__init__.py +0 -0
- qwak_sdk/commands/automations/list/_logic.py +36 -0
- qwak_sdk/commands/automations/list/ui.py +21 -0
- qwak_sdk/commands/automations/register/__init__.py +0 -0
- qwak_sdk/commands/automations/register/_logic.py +43 -0
- qwak_sdk/commands/automations/register/ui.py +44 -0
- qwak_sdk/commands/feature_store/__init__.py +0 -0
- qwak_sdk/commands/feature_store/backfill/__init__.py +0 -0
- qwak_sdk/commands/feature_store/backfill/_logic.py +140 -0
- qwak_sdk/commands/feature_store/backfill/streaming/__init__.py +0 -0
- qwak_sdk/commands/feature_store/backfill/streaming/_logic.py +50 -0
- qwak_sdk/commands/feature_store/backfill/streaming/ui.py +67 -0
- qwak_sdk/commands/feature_store/backfill/ui.py +146 -0
- qwak_sdk/commands/feature_store/delete/__init__.py +0 -0
- qwak_sdk/commands/feature_store/delete/_logic.py +104 -0
- qwak_sdk/commands/feature_store/delete/ui.py +40 -0
- qwak_sdk/commands/feature_store/execution/__init__.py +0 -0
- qwak_sdk/commands/feature_store/execution/ui.py +19 -0
- qwak_sdk/commands/feature_store/feature_store_command_group.py +29 -0
- qwak_sdk/commands/feature_store/list/__init__.py +0 -0
- qwak_sdk/commands/feature_store/list/ui.py +140 -0
- qwak_sdk/commands/feature_store/pause/__init__.py +0 -0
- qwak_sdk/commands/feature_store/pause/ui.py +18 -0
- qwak_sdk/commands/feature_store/register/__init__.py +0 -0
- qwak_sdk/commands/feature_store/register/_logic.py +367 -0
- qwak_sdk/commands/feature_store/register/ui.py +111 -0
- qwak_sdk/commands/feature_store/resume/__init__.py +0 -0
- qwak_sdk/commands/feature_store/resume/ui.py +18 -0
- qwak_sdk/commands/feature_store/trigger/__init__.py +0 -0
- qwak_sdk/commands/feature_store/trigger/ui.py +39 -0
- qwak_sdk/commands/models/__init__.py +0 -0
- qwak_sdk/commands/models/build/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/build_steps.py +42 -0
- qwak_sdk/commands/models/build/_logic/client_logs/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/client_logs/cli_phase_run_handler.py +123 -0
- qwak_sdk/commands/models/build/_logic/client_logs/cli_trigger_build_logger.py +19 -0
- qwak_sdk/commands/models/build/_logic/client_logs/logger.py +88 -0
- qwak_sdk/commands/models/build/_logic/client_logs/messages.py +36 -0
- qwak_sdk/commands/models/build/_logic/client_logs/spinner.py +14 -0
- qwak_sdk/commands/models/build/_logic/client_logs/trigger_build_logger.py +54 -0
- qwak_sdk/commands/models/build/_logic/client_logs/utils.py +12 -0
- qwak_sdk/commands/models/build/_logic/phase/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/__init__.py +20 -0
- qwak_sdk/commands/models/build/_logic/phase/a_fetch_model_code/get_sdk_version_step.py +14 -0
- qwak_sdk/commands/models/build/_logic/phase/b_remote_register_qwak_build/__init__.py +16 -0
- qwak_sdk/commands/models/build/_logic/phase/c_deploy/__init__.py +6 -0
- qwak_sdk/commands/models/build/_logic/phase/c_deploy/build_polling_status.py +55 -0
- qwak_sdk/commands/models/build/_logic/phase/c_deploy/deploy_build.py +61 -0
- qwak_sdk/commands/models/build/_logic/util/__init__.py +0 -0
- qwak_sdk/commands/models/build/_logic/util/protobuf_factory.py +45 -0
- qwak_sdk/commands/models/build/_logic/util/step_decorator.py +60 -0
- qwak_sdk/commands/models/build/_logic/util/text.py +9 -0
- qwak_sdk/commands/models/build/_logic/wait_until_finished.py +27 -0
- qwak_sdk/commands/models/build/ui.py +337 -0
- qwak_sdk/commands/models/builds/__init__.py +0 -0
- qwak_sdk/commands/models/builds/builds_commands_group.py +16 -0
- qwak_sdk/commands/models/builds/cancel/__init__.py +0 -0
- qwak_sdk/commands/models/builds/cancel/_logic.py +5 -0
- qwak_sdk/commands/models/builds/cancel/ui.py +15 -0
- qwak_sdk/commands/models/builds/logs/__init__.py +0 -0
- qwak_sdk/commands/models/builds/logs/ui.py +35 -0
- qwak_sdk/commands/models/builds/status/__init__.py +0 -0
- qwak_sdk/commands/models/builds/status/_logic.py +6 -0
- qwak_sdk/commands/models/builds/status/ui.py +39 -0
- qwak_sdk/commands/models/create/__init__.py +0 -0
- qwak_sdk/commands/models/create/_logic.py +36 -0
- qwak_sdk/commands/models/create/ui.py +43 -0
- qwak_sdk/commands/models/delete/__init__.py +0 -0
- qwak_sdk/commands/models/delete/_logic.py +5 -0
- qwak_sdk/commands/models/delete/ui.py +25 -0
- qwak_sdk/commands/models/deployments/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/advance_deployment_options_handler.py +31 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/base_deploy_executor.py +68 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/deploy_config.py +261 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/deployment.py +405 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/deployment_message_helpers.py +114 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/deployment_response_handler.py +156 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/deployment_size_mapper.py +96 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/get_latest_successful_build.py +28 -0
- qwak_sdk/commands/models/deployments/deploy/_logic/local_deployment.py +193 -0
- qwak_sdk/commands/models/deployments/deploy/batch/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/batch/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/batch/_logic/advanced_deployment_mapper.py +15 -0
- qwak_sdk/commands/models/deployments/deploy/batch/_logic/deploy_executor.py +24 -0
- qwak_sdk/commands/models/deployments/deploy/batch/ui.py +126 -0
- qwak_sdk/commands/models/deployments/deploy/deploy_commands_group.py +19 -0
- qwak_sdk/commands/models/deployments/deploy/realtime/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/realtime/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/realtime/_logic/advanced_deployment_mapper.py +21 -0
- qwak_sdk/commands/models/deployments/deploy/realtime/_logic/deploy_executor.py +24 -0
- qwak_sdk/commands/models/deployments/deploy/realtime/_logic/serving_strategy_mapper.py +75 -0
- qwak_sdk/commands/models/deployments/deploy/realtime/ui.py +209 -0
- qwak_sdk/commands/models/deployments/deploy/streaming/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/streaming/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/deploy/streaming/_logic/deploy_executor.py +24 -0
- qwak_sdk/commands/models/deployments/deploy/streaming/_logic/serving_strategy_mapper.py +38 -0
- qwak_sdk/commands/models/deployments/deploy/streaming/ui.py +213 -0
- qwak_sdk/commands/models/deployments/undeploy/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/undeploy/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/deployments/undeploy/_logic/request_undeploy.py +249 -0
- qwak_sdk/commands/models/deployments/undeploy/ui.py +72 -0
- qwak_sdk/commands/models/describe/__init__.py +0 -0
- qwak_sdk/commands/models/describe/_logic.py +169 -0
- qwak_sdk/commands/models/describe/ui.py +35 -0
- qwak_sdk/commands/models/executions/__init__.py +0 -0
- qwak_sdk/commands/models/executions/cancel/__init__.py +0 -0
- qwak_sdk/commands/models/executions/cancel/_logic.py +9 -0
- qwak_sdk/commands/models/executions/cancel/ui.py +27 -0
- qwak_sdk/commands/models/executions/execution_commands_group.py +24 -0
- qwak_sdk/commands/models/executions/report/__init__.py +0 -0
- qwak_sdk/commands/models/executions/report/_logic.py +14 -0
- qwak_sdk/commands/models/executions/report/ui.py +43 -0
- qwak_sdk/commands/models/executions/start/__init__.py +0 -0
- qwak_sdk/commands/models/executions/start/_logic.py +81 -0
- qwak_sdk/commands/models/executions/start/ui.py +208 -0
- qwak_sdk/commands/models/executions/status/__init__.py +0 -0
- qwak_sdk/commands/models/executions/status/_logic.py +13 -0
- qwak_sdk/commands/models/executions/status/ui.py +27 -0
- qwak_sdk/commands/models/init/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/initialize_model_structure.py +40 -0
- qwak_sdk/commands/models/init/_logic/template/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/churn/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/churn/cookiecutter.json +3 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/conda.yml +10 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/data.csv +1001 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/model.py +95 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/tests/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/tests/it/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/tests/it/test_churn.py +32 -0
- qwak_sdk/commands/models/init/_logic/template/credit_risk/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/credit_risk/cookiecutter.json +3 -0
- qwak_sdk/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
- qwak_sdk/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/conda.yml +11 -0
- qwak_sdk/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/data.csv +1001 -0
- qwak_sdk/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/model.py +108 -0
- qwak_sdk/commands/models/init/_logic/template/general/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/general/cookiecutter.json +6 -0
- qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.main_directory}}/__init__.py +5 -0
- qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.main_directory}}/conda.yml +8 -0
- qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.main_directory}}/model.py +66 -0
- qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.test_directory}}/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.test_directory}}/test_qwak_model.py +5 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/cookiecutter.json +3 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/main/conda.yml +11 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/main/model.py +98 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/tests/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/tests/it/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/tests/it/test_titanic.py +24 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/cookiecutter.json +3 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/main/model.py +98 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/main/pyproject.toml +20 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/tests/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/tests/it/__init__.py +0 -0
- qwak_sdk/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/tests/it/test_titanic.py +25 -0
- qwak_sdk/commands/models/init/ui.py +61 -0
- qwak_sdk/commands/models/list/__init__.py +0 -0
- qwak_sdk/commands/models/list/_logic.py +5 -0
- qwak_sdk/commands/models/list/ui.py +40 -0
- qwak_sdk/commands/models/list_models/__init__.py +0 -0
- qwak_sdk/commands/models/list_models/_logic.py +5 -0
- qwak_sdk/commands/models/list_models/ui.py +60 -0
- qwak_sdk/commands/models/metadata/__init__.py +0 -0
- qwak_sdk/commands/models/metadata/_logic.py +5 -0
- qwak_sdk/commands/models/metadata/ui.py +60 -0
- qwak_sdk/commands/models/models_command_group.py +44 -0
- qwak_sdk/commands/models/runtime/__init__.py +0 -0
- qwak_sdk/commands/models/runtime/logs/__init__.py +0 -0
- qwak_sdk/commands/models/runtime/logs/ui.py +63 -0
- qwak_sdk/commands/models/runtime/runtime_commands_group.py +17 -0
- qwak_sdk/commands/models/runtime/update/__init__.py +0 -0
- qwak_sdk/commands/models/runtime/update/_logic.py +9 -0
- qwak_sdk/commands/models/runtime/update/ui.py +15 -0
- qwak_sdk/commands/projects/__init__.py +0 -0
- qwak_sdk/commands/projects/create/__init__.py +0 -0
- qwak_sdk/commands/projects/create/_logic.py +9 -0
- qwak_sdk/commands/projects/create/ui.py +68 -0
- qwak_sdk/commands/projects/delete/__init__.py +0 -0
- qwak_sdk/commands/projects/delete/_logic.py +6 -0
- qwak_sdk/commands/projects/delete/ui.py +24 -0
- qwak_sdk/commands/projects/list/__init__.py +0 -0
- qwak_sdk/commands/projects/list/_logic.py +6 -0
- qwak_sdk/commands/projects/list/ui.py +45 -0
- qwak_sdk/commands/projects/projects_command_group.py +19 -0
- qwak_sdk/commands/secrets/__init__.py +0 -0
- qwak_sdk/commands/secrets/delete/__init__.py +0 -0
- qwak_sdk/commands/secrets/delete/_logic.py +5 -0
- qwak_sdk/commands/secrets/delete/ui.py +21 -0
- qwak_sdk/commands/secrets/get/__init__.py +0 -0
- qwak_sdk/commands/secrets/get/_logic.py +5 -0
- qwak_sdk/commands/secrets/get/ui.py +17 -0
- qwak_sdk/commands/secrets/secrets_commands_group.py +19 -0
- qwak_sdk/commands/secrets/set/__init__.py +0 -0
- qwak_sdk/commands/secrets/set/_logic.py +5 -0
- qwak_sdk/commands/secrets/set/ui.py +16 -0
- qwak_sdk/commands/ui_tools.py +18 -0
- qwak_sdk/commands/workspaces/__init__.py +0 -0
- qwak_sdk/commands/workspaces/_logic/__init__.py +0 -0
- qwak_sdk/commands/workspaces/_logic/tools.py +44 -0
- qwak_sdk/commands/workspaces/_logic/workspace_validations.py +41 -0
- qwak_sdk/commands/workspaces/config/__init__.py +0 -0
- qwak_sdk/commands/workspaces/config/workspace_config.py +35 -0
- qwak_sdk/commands/workspaces/create/__init__.py +0 -0
- qwak_sdk/commands/workspaces/create/_logic.py +54 -0
- qwak_sdk/commands/workspaces/create/ui.py +48 -0
- qwak_sdk/commands/workspaces/delete/__init__.py +0 -0
- qwak_sdk/commands/workspaces/delete/_logic.py +30 -0
- qwak_sdk/commands/workspaces/delete/ui.py +23 -0
- qwak_sdk/commands/workspaces/start/__init__.py +0 -0
- qwak_sdk/commands/workspaces/start/_logic.py +30 -0
- qwak_sdk/commands/workspaces/start/ui.py +23 -0
- qwak_sdk/commands/workspaces/stop/__init__.py +0 -0
- qwak_sdk/commands/workspaces/stop/_logic.py +30 -0
- qwak_sdk/commands/workspaces/stop/ui.py +23 -0
- qwak_sdk/commands/workspaces/update/__init__.py +0 -0
- qwak_sdk/commands/workspaces/update/_logic.py +82 -0
- qwak_sdk/commands/workspaces/update/ui.py +57 -0
- qwak_sdk/commands/workspaces/workspaces_commands_group.py +23 -0
- qwak_sdk/exceptions/__init__.py +11 -0
- qwak_sdk/exceptions/qwak_command_exception.py +2 -0
- qwak_sdk/exceptions/qwak_deploy_new_build_failed.py +5 -0
- qwak_sdk/exceptions/qwak_resource_not_found.py +2 -0
- qwak_sdk/inner/__init__.py +0 -0
- qwak_sdk/inner/file_registry.py +98 -0
- qwak_sdk/inner/tools/__init__.py +0 -0
- qwak_sdk/inner/tools/cli_tools.py +220 -0
- qwak_sdk/inner/tools/config_handler.py +27 -0
- qwak_sdk/inner/tools/dataclasses_utils.py +21 -0
- qwak_sdk/inner/tools/logger/__init__.py +3 -0
- qwak_sdk/inner/tools/logger/logger.py +269 -0
- qwak_sdk/inner/tools/logger/logging.yml +79 -0
- qwak_sdk/inner/tools/tracking.py +47 -0
- qwak_sdk/main.py +9 -0
- qwak_sdk/tools/__init__.py +0 -0
- qwak_sdk/tools/colors.py +13 -0
- qwak_sdk/tools/files.py +63 -0
- qwak_sdk/tools/log_handling.py +159 -0
- qwak_sdk/tools/utils.py +42 -0
- qwak_sdk-0.5.102.dist-info/METADATA +51 -0
- qwak_sdk-0.5.102.dist-info/RECORD +328 -0
- qwak_sdk-0.5.102.dist-info/WHEEL +4 -0
- qwak_sdk-0.5.102.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
from contextlib import contextmanager
|
|
2
|
+
from logging import Logger
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from qwak.inner.build_logic.interface.build_phase import BuildPhase
|
|
6
|
+
from qwak.inner.build_logic.interface.phase_run_handler import PhaseRunHandler
|
|
7
|
+
from qwak.inner.build_logic.phases.phases_pipeline import PhasesPipeline
|
|
8
|
+
from yaspin import yaspin
|
|
9
|
+
|
|
10
|
+
from qwak_sdk.tools.colors import Color
|
|
11
|
+
from .cli_trigger_build_logger import CliTriggerBuildLogger
|
|
12
|
+
from .messages import (
|
|
13
|
+
FAILED_CONTACT_QWAK_SUPPORT,
|
|
14
|
+
)
|
|
15
|
+
from .utils import zip_logs
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CLIPhaseRunHandler(PhaseRunHandler):
|
|
19
|
+
BUILD_IN_PROGRESS_FORMAT = "Build phase in progress: {}"
|
|
20
|
+
BUILD_FINISHED_FORMAT = "Phase successfully finished: {} after {} seconds"
|
|
21
|
+
KEYBOARD_INTERRUPT_FORMAT = "\n{color}Stopping Qwak build (ctrl-c)"
|
|
22
|
+
BUILD_FAILURE_FORMAT = "Build phase failed: {} after {} seconds"
|
|
23
|
+
PIPELINE_ERROR = "\n{color}{ex}"
|
|
24
|
+
SPINNER_FINISH = "✅"
|
|
25
|
+
SPINNER_FAIL = "💥"
|
|
26
|
+
SPINNER_OK = "‼️"
|
|
27
|
+
|
|
28
|
+
def __init__(self, python_logger: Logger, log_path: Path, verbose: int, json_logs: bool):
|
|
29
|
+
self.sp = None
|
|
30
|
+
self.build_logger = None
|
|
31
|
+
self.log_path = str(log_path)
|
|
32
|
+
self.python_logger = python_logger
|
|
33
|
+
self.json_logs = json_logs
|
|
34
|
+
self.verbose = verbose
|
|
35
|
+
|
|
36
|
+
@contextmanager
|
|
37
|
+
def handle_current_phase(self, phase: PhasesPipeline):
|
|
38
|
+
build_logger = CliTriggerBuildLogger(
|
|
39
|
+
self.python_logger,
|
|
40
|
+
prefix="" if self.json_logs else phase.build_phase.description,
|
|
41
|
+
build_phase=phase.build_phase,
|
|
42
|
+
)
|
|
43
|
+
show = (self.verbose == 0 and not self.json_logs)
|
|
44
|
+
text = phase.build_phase.description
|
|
45
|
+
if show:
|
|
46
|
+
with yaspin(text=text, color="blue", timer=True).bold as sp:
|
|
47
|
+
self.sp = sp
|
|
48
|
+
build_logger.set_spinner(sp)
|
|
49
|
+
self.build_logger = build_logger
|
|
50
|
+
yield
|
|
51
|
+
else:
|
|
52
|
+
self.build_logger = build_logger
|
|
53
|
+
yield
|
|
54
|
+
|
|
55
|
+
def handle_phase_in_progress(self, build_phase: BuildPhase):
|
|
56
|
+
logger = self.build_logger or self.python_logger
|
|
57
|
+
logger.debug(
|
|
58
|
+
self.BUILD_IN_PROGRESS_FORMAT.format(build_phase.name)
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def handle_phase_finished_successfully(
|
|
62
|
+
self, build_phase: BuildPhase, duration_in_seconds: int
|
|
63
|
+
):
|
|
64
|
+
if self.sp:
|
|
65
|
+
self.sp.ok(self.SPINNER_FINISH)
|
|
66
|
+
|
|
67
|
+
logger = self.build_logger or self.python_logger
|
|
68
|
+
logger.debug(
|
|
69
|
+
self.BUILD_FINISHED_FORMAT.format(build_phase.name, duration_in_seconds))
|
|
70
|
+
|
|
71
|
+
def _report_failure(self, build_phase: BuildPhase, duration_in_seconds: int):
|
|
72
|
+
logger = self.build_logger or self.python_logger
|
|
73
|
+
logger.debug(
|
|
74
|
+
self.BUILD_FAILURE_FORMAT.format(build_phase.name, duration_in_seconds))
|
|
75
|
+
|
|
76
|
+
def handle_contact_support_error(
|
|
77
|
+
self, build_id: str, build_phase: BuildPhase, ex: BaseException, duration_in_seconds: int
|
|
78
|
+
):
|
|
79
|
+
print(f"\n{ex}\n{FAILED_CONTACT_QWAK_SUPPORT.format(build_id=build_id, log_file=Path(self.log_path).parent / build_id)}")
|
|
80
|
+
zip_logs(log_path=self.log_path, build_id=build_id)
|
|
81
|
+
self._report_failure(build_phase, duration_in_seconds)
|
|
82
|
+
exit(1)
|
|
83
|
+
|
|
84
|
+
def handle_remote_build_error(
|
|
85
|
+
self, build_id: str, build_phase: BuildPhase, ex: BaseException, duration_in_seconds: int
|
|
86
|
+
):
|
|
87
|
+
if self.sp:
|
|
88
|
+
self.sp.fail(self.SPINNER_FAIL)
|
|
89
|
+
print(self.PIPELINE_ERROR.format(color=Color.RED, ex=ex))
|
|
90
|
+
else:
|
|
91
|
+
print(f"\n{ex}")
|
|
92
|
+
self._report_failure(build_phase, duration_in_seconds)
|
|
93
|
+
exit(1)
|
|
94
|
+
|
|
95
|
+
def handle_keyboard_interrupt(
|
|
96
|
+
self, build_id: str, build_phase: BuildPhase, duration_in_seconds: int
|
|
97
|
+
):
|
|
98
|
+
print(self.KEYBOARD_INTERRUPT_FORMAT.format(color=Color.RED))
|
|
99
|
+
zip_logs(log_path=self.log_path, build_id=build_id)
|
|
100
|
+
self._report_failure(build_phase, duration_in_seconds)
|
|
101
|
+
exit(1)
|
|
102
|
+
|
|
103
|
+
def handle_pipeline_exception(
|
|
104
|
+
self, build_id: str, build_phase: BuildPhase, ex: BaseException, duration_in_seconds: int
|
|
105
|
+
):
|
|
106
|
+
if self.sp:
|
|
107
|
+
self.sp.fail("💥")
|
|
108
|
+
print(f"\n{Color.RED}{ex}")
|
|
109
|
+
zip_logs(
|
|
110
|
+
log_path=self.log_path,
|
|
111
|
+
build_id=build_id,
|
|
112
|
+
)
|
|
113
|
+
self._report_failure(build_phase, duration_in_seconds)
|
|
114
|
+
exit(1)
|
|
115
|
+
|
|
116
|
+
def handle_pipeline_quiet_exception(
|
|
117
|
+
self, build_id: str, build_phase: BuildPhase, ex: BaseException, duration_in_seconds: int
|
|
118
|
+
):
|
|
119
|
+
if self.sp:
|
|
120
|
+
self.sp.ok(self.SPINNER_OK)
|
|
121
|
+
print(self.PIPELINE_ERROR.format(color=Color.RED, ex=ex))
|
|
122
|
+
self._report_failure(build_phase, duration_in_seconds)
|
|
123
|
+
exit(1)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from logging import Logger
|
|
2
|
+
|
|
3
|
+
from qwak.inner.build_logic.build_loggers.trigger_build_logger import TriggerBuildLogger
|
|
4
|
+
from qwak.inner.build_logic.interface.build_phase import BuildPhase
|
|
5
|
+
from yaspin.core import Yaspin
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CliTriggerBuildLogger(TriggerBuildLogger):
|
|
9
|
+
def __init__(self, logger: Logger, prefix: str, build_phase: BuildPhase, verbose: int = 0,
|
|
10
|
+
json_logs: bool = False) -> None:
|
|
11
|
+
super().__init__(logger, prefix, build_phase, verbose, json_logs)
|
|
12
|
+
self.spinner = None
|
|
13
|
+
|
|
14
|
+
def set_spinner(self, spinner: Yaspin):
|
|
15
|
+
self.spinner = spinner
|
|
16
|
+
|
|
17
|
+
def spinner_text(self, line: str) -> None:
|
|
18
|
+
if self.spinner:
|
|
19
|
+
self.spinner.text = f"{self.prefix}{line}"
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
import platform
|
|
5
|
+
import shutil
|
|
6
|
+
import sys
|
|
7
|
+
import uuid
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from qwak.inner.build_config.build_config_v1 import BuildConfigV1
|
|
11
|
+
from qwak.inner.build_logic.constants.host_resource import HOST_QWAK_HIDDEN_FOLDER
|
|
12
|
+
|
|
13
|
+
from qwak_sdk import __version__ as qwak_sdk_version
|
|
14
|
+
from qwak_sdk.inner.tools.logger import setup_qwak_logger
|
|
15
|
+
from qwak_sdk.inner.tools.logger.logger import (
|
|
16
|
+
BUILD_LOCAL_FILE_HANDLER_NAME,
|
|
17
|
+
BUILD_LOCAL_LOGGER_NAME,
|
|
18
|
+
CONSOLE_HANDLER_NAME,
|
|
19
|
+
REMOTE_CONSOLE_HANDLER_NAME,
|
|
20
|
+
REMOTE_LOGGER_NAME,
|
|
21
|
+
VERBOSITY_LEVEL_MAPPING,
|
|
22
|
+
get_qwak_logger,
|
|
23
|
+
non_qwak_logger_enabled,
|
|
24
|
+
set_file_handler_log_file,
|
|
25
|
+
set_handler_verbosity,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
BUILDS_LOGS = HOST_QWAK_HIDDEN_FOLDER / "logs" / "build"
|
|
29
|
+
BUILD_LOG_NAME = "build.log"
|
|
30
|
+
MAX_LOGS_NUMBER = 15
|
|
31
|
+
DEBUG_LEVEL = 2
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@contextlib.contextmanager
|
|
35
|
+
def get_build_logger(config: BuildConfigV1, json_logs: bool):
|
|
36
|
+
log_path = BUILDS_LOGS / config.build_properties.model_id / str(uuid.uuid4())[:4]
|
|
37
|
+
log_path.mkdir(parents=True, exist_ok=True)
|
|
38
|
+
try:
|
|
39
|
+
(log_path / "build_config.yml").write_text(config.to_yaml())
|
|
40
|
+
log_system_information(log_path)
|
|
41
|
+
|
|
42
|
+
log_file = log_path / BUILD_LOG_NAME
|
|
43
|
+
setup_qwak_logger()
|
|
44
|
+
yield setup_logger(
|
|
45
|
+
log_file=log_file, verbosity_level=config.verbose, json_logs=json_logs
|
|
46
|
+
), log_path
|
|
47
|
+
finally:
|
|
48
|
+
# Cleanup - Save only x last zips
|
|
49
|
+
logs_zip_sorted_by_data = sorted(
|
|
50
|
+
BUILDS_LOGS.rglob("**/*"), key=os.path.getmtime
|
|
51
|
+
)[:-MAX_LOGS_NUMBER]
|
|
52
|
+
path: Path
|
|
53
|
+
for path in logs_zip_sorted_by_data:
|
|
54
|
+
if path.is_file():
|
|
55
|
+
os.remove(path)
|
|
56
|
+
elif path.is_dir():
|
|
57
|
+
shutil.rmtree(path, ignore_errors=True)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def setup_logger(
|
|
61
|
+
log_file: Path, verbosity_level: int, json_logs: bool
|
|
62
|
+
) -> logging.Logger:
|
|
63
|
+
# Init logger
|
|
64
|
+
fallback_logger_name = (
|
|
65
|
+
BUILD_LOCAL_LOGGER_NAME if not json_logs else REMOTE_LOGGER_NAME
|
|
66
|
+
)
|
|
67
|
+
logger = get_qwak_logger(fallback_logger_name=fallback_logger_name)
|
|
68
|
+
|
|
69
|
+
if not non_qwak_logger_enabled():
|
|
70
|
+
if logger.name == BUILD_LOCAL_LOGGER_NAME:
|
|
71
|
+
set_file_handler_log_file(logger, BUILD_LOCAL_FILE_HANDLER_NAME, log_file)
|
|
72
|
+
set_handler_verbosity(
|
|
73
|
+
logger, CONSOLE_HANDLER_NAME, VERBOSITY_LEVEL_MAPPING[verbosity_level]
|
|
74
|
+
)
|
|
75
|
+
elif logger.name == REMOTE_LOGGER_NAME and json_logs:
|
|
76
|
+
set_handler_verbosity(
|
|
77
|
+
logger,
|
|
78
|
+
REMOTE_CONSOLE_HANDLER_NAME,
|
|
79
|
+
VERBOSITY_LEVEL_MAPPING[DEBUG_LEVEL],
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
return logger
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def log_system_information(destination: Path):
|
|
86
|
+
(destination / "python_version").write_text(sys.version)
|
|
87
|
+
(destination / "qwak_sdk_version").write_text(qwak_sdk_version)
|
|
88
|
+
(destination / "os_detail").write_text(platform.platform())
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
BUILD_LOGS_URL = (
|
|
2
|
+
"{base_url}/models/{model_id}/build/{build_id}"
|
|
3
|
+
)
|
|
4
|
+
|
|
5
|
+
SUCCESS_MSG_REMOTE = """
|
|
6
|
+
Build ID \033[4m{build_id}\033[0m triggered remotely
|
|
7
|
+
|
|
8
|
+
########### Follow build logs in the CLI
|
|
9
|
+
qwak models builds logs -b {build_id} --follow
|
|
10
|
+
|
|
11
|
+
########### Follow build logs in the platform
|
|
12
|
+
{base_url}/models/{model_id}/build/{build_id}
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
SUCCESS_MSG_REMOTE_WITH_DEPLOY = """
|
|
16
|
+
Build ID \033[4m{build_id}\033[0m finished successfully and deployed
|
|
17
|
+
|
|
18
|
+
########### View the model using platform
|
|
19
|
+
{base_url}/models/{model_id}
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
FAILED_CONTACT_QWAK_SUPPORT = """
|
|
23
|
+
Build ID \033[4m{build_id}\033[0m failed!!
|
|
24
|
+
You can share the logs from \033[4m{log_file}.zip\033[0m with the support team.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
FAILED_REMOTE_BUILD_SUGGESTION = """
|
|
28
|
+
Your build failed. Check the failure reason in the platform:
|
|
29
|
+
{base_url}/models/{model_id}/build/{build_id}
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
FAILED_DEPLOY_BUILD_SUGGESTION = """
|
|
33
|
+
Deploying the build failed. Check the failure reason in the platform:
|
|
34
|
+
{base_url}/models/{model_id}?tabId=1
|
|
35
|
+
Try and redeploy this build either from the platform or the CLI
|
|
36
|
+
"""
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from contextlib import contextmanager
|
|
2
|
+
from typing import Generator, Optional
|
|
3
|
+
|
|
4
|
+
from yaspin import yaspin
|
|
5
|
+
from yaspin.core import Yaspin
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@contextmanager
|
|
9
|
+
def spinner(text: Optional[str], show: bool) -> Generator[Yaspin, None, None]:
|
|
10
|
+
if show:
|
|
11
|
+
with yaspin(text=text, color="blue", timer=True).bold as sp:
|
|
12
|
+
yield sp
|
|
13
|
+
else:
|
|
14
|
+
yield
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from logging import Logger
|
|
3
|
+
|
|
4
|
+
from qwak.inner.build_logic.interface.build_logger_interface import BuildLogger
|
|
5
|
+
from qwak.inner.build_logic.interface.build_phase import BuildPhase
|
|
6
|
+
from yaspin.core import Yaspin
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
PREFIX_FORMAT = "{prefix} - "
|
|
10
|
+
EXCEPTION_FORMAT = """Message: {line}
|
|
11
|
+
Exception: {e}
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TriggerBuildLogger(BuildLogger):
|
|
16
|
+
def __init__(
|
|
17
|
+
self, logger: Logger, prefix: str, build_phase: BuildPhase, verbose: int = 0, json_logs: bool = False,
|
|
18
|
+
) -> None:
|
|
19
|
+
self.logger = logging.LoggerAdapter(
|
|
20
|
+
logger,
|
|
21
|
+
{
|
|
22
|
+
"phase": build_phase.description,
|
|
23
|
+
"phase_id": build_phase.phase_id,
|
|
24
|
+
},
|
|
25
|
+
)
|
|
26
|
+
self.prefix = PREFIX_FORMAT.format(prefix=prefix) if prefix else ""
|
|
27
|
+
self.spinner = None
|
|
28
|
+
self.verbose = verbose
|
|
29
|
+
self.json_logs = json_logs
|
|
30
|
+
|
|
31
|
+
def set_spinner(self, spinner: Yaspin):
|
|
32
|
+
self.spinner = spinner
|
|
33
|
+
|
|
34
|
+
def exception(self, line: str, e: BaseException) -> None:
|
|
35
|
+
self.logger.error(
|
|
36
|
+
EXCEPTION_FORMAT.format(line=line, e=e),
|
|
37
|
+
exc_info=False,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def error(self, line: str) -> None:
|
|
41
|
+
self.logger.error(f"{self.prefix}{line}")
|
|
42
|
+
|
|
43
|
+
def warning(self, line: str) -> None:
|
|
44
|
+
self.logger.warning(f"{self.prefix}{line}")
|
|
45
|
+
|
|
46
|
+
def info(self, line: str) -> None:
|
|
47
|
+
self.logger.info(f"{self.prefix}{line}")
|
|
48
|
+
|
|
49
|
+
def debug(self, line: str) -> None:
|
|
50
|
+
self.logger.debug(f"{self.prefix}{line}")
|
|
51
|
+
|
|
52
|
+
def spinner_text(self, line: str) -> None:
|
|
53
|
+
if self.spinner:
|
|
54
|
+
self.spinner.text = f"{self.prefix}{line}"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def zip_logs(log_path: str, build_id: str):
|
|
6
|
+
if build_id:
|
|
7
|
+
shutil.make_archive(
|
|
8
|
+
base_name=str(Path(log_path).parent / build_id),
|
|
9
|
+
format="zip",
|
|
10
|
+
root_dir=log_path,
|
|
11
|
+
)
|
|
12
|
+
shutil.rmtree(log_path, ignore_errors=True)
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from qwak.inner.build_logic.interface.step_inteface import Step
|
|
4
|
+
from qwak.inner.build_logic.phases.phase_010_fetch_model.fetch_model_step import FetchModelStep
|
|
5
|
+
from qwak.inner.build_logic.phases.phase_010_fetch_model.post_fetch_validation_step import PostFetchValidationStep
|
|
6
|
+
from qwak.inner.build_logic.phases.phase_010_fetch_model.pre_fetch_validation_step import PreFetchValidationStep
|
|
7
|
+
|
|
8
|
+
from qwak_sdk.commands.models.build._logic.phase.a_fetch_model_code.get_sdk_version_step import SdkVersionStep
|
|
9
|
+
from qwak_sdk.commands.models.build._logic.util.step_decorator import add_decorator_to_steps
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_fetch_model_code_steps() -> List[Step]:
|
|
13
|
+
phase_steps = [
|
|
14
|
+
SdkVersionStep(),
|
|
15
|
+
PreFetchValidationStep(),
|
|
16
|
+
FetchModelStep(),
|
|
17
|
+
PostFetchValidationStep(),
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
return add_decorator_to_steps(phase_steps)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from qwak.inner.build_logic.interface.step_inteface import Step
|
|
2
|
+
|
|
3
|
+
from qwak_sdk import __version__ as qwak_sdk_version
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SdkVersionStep(Step):
|
|
7
|
+
def description(self) -> str:
|
|
8
|
+
return "Getting SDK Version"
|
|
9
|
+
|
|
10
|
+
def execute(self) -> None:
|
|
11
|
+
self.build_logger.debug(
|
|
12
|
+
"Getting sdk version"
|
|
13
|
+
)
|
|
14
|
+
self.context.qwak_sdk_version = qwak_sdk_version
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from qwak.inner.build_logic.phases.phase_020_remote_register_qwak_build.cleanup_step import CleanupStep
|
|
2
|
+
from qwak.inner.build_logic.phases.phase_020_remote_register_qwak_build.start_remote_build_step import \
|
|
3
|
+
StartRemoteBuildStep
|
|
4
|
+
from qwak.inner.build_logic.phases.phase_020_remote_register_qwak_build.upload_step import UploadStep
|
|
5
|
+
|
|
6
|
+
from ...util.step_decorator import add_decorator_to_steps
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_remote_register_qwak_build_steps():
|
|
10
|
+
phase_steps = [
|
|
11
|
+
UploadStep(),
|
|
12
|
+
StartRemoteBuildStep(),
|
|
13
|
+
CleanupStep(),
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
return add_decorator_to_steps(phase_steps)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
from _qwak_proto.qwak.build.v1.build_api_pb2 import GetBuildResponse
|
|
6
|
+
from _qwak_proto.qwak.build.v1.build_pb2 import BuildStatus
|
|
7
|
+
|
|
8
|
+
from qwak_sdk.commands.models.build._logic.client_logs.messages import (
|
|
9
|
+
FAILED_REMOTE_BUILD_SUGGESTION,
|
|
10
|
+
)
|
|
11
|
+
from qwak.inner.build_logic.interface.step_inteface import Step
|
|
12
|
+
from qwak.exceptions import QwakRemoteBuildFailedException
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BuildPollingStatusStep(Step):
|
|
16
|
+
FINITE_BUILD_STATUSES = {
|
|
17
|
+
BuildStatus.REMOTE_BUILD_CANCELLED,
|
|
18
|
+
BuildStatus.REMOTE_BUILD_TIMED_OUT,
|
|
19
|
+
BuildStatus.FAILED,
|
|
20
|
+
BuildStatus.SUCCESSFUL,
|
|
21
|
+
}
|
|
22
|
+
SLEEP_BETWEEN_STATUS_CHECK = 10
|
|
23
|
+
REMOTE_BUILD_FAILURE_EXCEPTION_FORMAT = "Your build failed with status {status}"
|
|
24
|
+
|
|
25
|
+
def description(self) -> str:
|
|
26
|
+
return "Polling on Build Status"
|
|
27
|
+
|
|
28
|
+
def execute(self) -> None:
|
|
29
|
+
self.build_logger.info("Waiting for build to finish")
|
|
30
|
+
status = self.wait_for_finite_build_status()
|
|
31
|
+
if status != BuildStatus.SUCCESSFUL:
|
|
32
|
+
raise QwakRemoteBuildFailedException(
|
|
33
|
+
message=self.REMOTE_BUILD_FAILURE_EXCEPTION_FORMAT.format(
|
|
34
|
+
status=BuildStatus.Name(status)
|
|
35
|
+
),
|
|
36
|
+
suggestion=FAILED_REMOTE_BUILD_SUGGESTION.format(
|
|
37
|
+
base_url=self.context.platform_url,
|
|
38
|
+
build_id=self.context.build_id,
|
|
39
|
+
model_id=self.context.model_id,
|
|
40
|
+
project_uuid=self.context.project_uuid,
|
|
41
|
+
),
|
|
42
|
+
)
|
|
43
|
+
self.build_logger.info("Your build finished successfully")
|
|
44
|
+
|
|
45
|
+
def wait_for_finite_build_status(self) -> BuildStatus:
|
|
46
|
+
self.build_logger.spinner_text(line="Waiting for build to finish")
|
|
47
|
+
while True:
|
|
48
|
+
result: GetBuildResponse = (
|
|
49
|
+
self.context.client_builds_orchestrator.get_build(self.context.build_id)
|
|
50
|
+
)
|
|
51
|
+
status: BuildStatus = result.build.build_status
|
|
52
|
+
if status in self.FINITE_BUILD_STATUSES:
|
|
53
|
+
return status
|
|
54
|
+
self.build_logger.debug(f"Build status is currently {BuildStatus.Name(status)}")
|
|
55
|
+
time.sleep(self.SLEEP_BETWEEN_STATUS_CHECK)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
from _qwak_proto.qwak.instance_template.instance_template_pb2 import (
|
|
6
|
+
InstanceTemplateSpec,
|
|
7
|
+
InstanceType,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from qwak_sdk.commands.models.build._logic.client_logs.messages import (
|
|
11
|
+
FAILED_DEPLOY_BUILD_SUGGESTION,
|
|
12
|
+
)
|
|
13
|
+
from qwak.inner.build_logic.interface.step_inteface import Step
|
|
14
|
+
from qwak_sdk.commands.models.deployments.deploy.realtime.ui import deploy_realtime
|
|
15
|
+
from qwak_sdk.exceptions.qwak_deploy_new_build_failed import (
|
|
16
|
+
QwakDeployNewBuildFailedException,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class DeployBuildStep(Step):
|
|
21
|
+
DEPLOY_FAILURE_EXCEPTION_MESSAGE = "Deploying the build failed due to {e}"
|
|
22
|
+
|
|
23
|
+
def description(self) -> str:
|
|
24
|
+
return "Deploying Build"
|
|
25
|
+
|
|
26
|
+
def execute(self) -> None:
|
|
27
|
+
self.build_logger.info(f"Deploying build {self.context.build_id}")
|
|
28
|
+
try:
|
|
29
|
+
if self.config.deployment_instance:
|
|
30
|
+
template_id = self.config.deployment_instance
|
|
31
|
+
else:
|
|
32
|
+
template_id = self.get_smallest_deployment_template_id()
|
|
33
|
+
deploy_config = {
|
|
34
|
+
"build_id": self.context.build_id,
|
|
35
|
+
"model_id": self.context.model_id,
|
|
36
|
+
"instance": template_id,
|
|
37
|
+
}
|
|
38
|
+
deploy_realtime(from_file=None, out_conf=False, sync=False, **deploy_config)
|
|
39
|
+
self.build_logger.info(f"Finished deploying build {self.context.build_id}")
|
|
40
|
+
except Exception as e:
|
|
41
|
+
raise QwakDeployNewBuildFailedException(
|
|
42
|
+
message=self.DEPLOY_FAILURE_EXCEPTION_MESSAGE.format(e=e),
|
|
43
|
+
suggestion=FAILED_DEPLOY_BUILD_SUGGESTION.format(
|
|
44
|
+
base_url=self.context.platform_url,
|
|
45
|
+
build_id=self.context.build_id,
|
|
46
|
+
model_id=self.context.model_id,
|
|
47
|
+
project_uuid=self.context.project_uuid,
|
|
48
|
+
),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
def get_smallest_deployment_template_id(self):
|
|
52
|
+
instances: List[
|
|
53
|
+
InstanceTemplateSpec
|
|
54
|
+
] = self.context.client_instance_template.list_instance_templates()
|
|
55
|
+
return list(
|
|
56
|
+
filter(
|
|
57
|
+
lambda template: template.order == 1
|
|
58
|
+
and template.instance_type == InstanceType.INSTANCE_TYPE_CPU,
|
|
59
|
+
instances,
|
|
60
|
+
)
|
|
61
|
+
)[0].id
|
|
File without changes
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from qwak.exceptions import QwakException
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def protobuf_factory(
|
|
5
|
+
protobuf_class, exclude_fields=None, include_only=None, mapping=None
|
|
6
|
+
):
|
|
7
|
+
def get_final_field_names(cls):
|
|
8
|
+
fields = dict(cls.__dataclass_fields__)
|
|
9
|
+
all_field_names = set(fields.keys())
|
|
10
|
+
excluded_fields = set(exclude_fields) if exclude_fields else set()
|
|
11
|
+
included_fields = set(include_only) if include_only else all_field_names
|
|
12
|
+
unrecognized_fields = included_fields.difference(all_field_names)
|
|
13
|
+
if unrecognized_fields:
|
|
14
|
+
raise QwakException(
|
|
15
|
+
f"Unknown fields were included: {list(unrecognized_fields)}"
|
|
16
|
+
)
|
|
17
|
+
return included_fields.difference(excluded_fields)
|
|
18
|
+
|
|
19
|
+
def protofy_decorator(cls):
|
|
20
|
+
if not hasattr(cls, "__dataclass_fields__"):
|
|
21
|
+
raise QwakException("Protofy must receive a dataclass")
|
|
22
|
+
|
|
23
|
+
fields_mapping = mapping if mapping else {}
|
|
24
|
+
final_field_names = get_final_field_names(cls)
|
|
25
|
+
|
|
26
|
+
def to_proto(self) -> protobuf_class:
|
|
27
|
+
final_fields = {}
|
|
28
|
+
for field_name in final_field_names:
|
|
29
|
+
field_val = self.__getattribute__(field_name)
|
|
30
|
+
field_name = (
|
|
31
|
+
fields_mapping[field_name]
|
|
32
|
+
if field_name in fields_mapping
|
|
33
|
+
else field_name
|
|
34
|
+
)
|
|
35
|
+
final_fields[field_name] = (
|
|
36
|
+
field_val.to_proto()
|
|
37
|
+
if hasattr(field_val, "to_proto")
|
|
38
|
+
else field_val
|
|
39
|
+
)
|
|
40
|
+
return protobuf_class(**final_fields)
|
|
41
|
+
|
|
42
|
+
setattr(cls, "to_proto", to_proto)
|
|
43
|
+
return cls
|
|
44
|
+
|
|
45
|
+
return protofy_decorator
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shutil
|
|
3
|
+
from functools import wraps
|
|
4
|
+
from typing import List
|
|
5
|
+
|
|
6
|
+
from qwak.exceptions import QuietError
|
|
7
|
+
from qwak.inner.build_logic.interface.build_logger_interface import BuildLogger
|
|
8
|
+
from qwak.inner.build_logic.interface.step_inteface import Step
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def step_exception_handler_decorator(step: Step):
|
|
12
|
+
execute_func = step.execute
|
|
13
|
+
|
|
14
|
+
@wraps(execute_func)
|
|
15
|
+
def inner_function(*args, **kwargs):
|
|
16
|
+
try:
|
|
17
|
+
execute_func(*args, **kwargs)
|
|
18
|
+
except BaseException as e:
|
|
19
|
+
if not isinstance(e, QuietError):
|
|
20
|
+
build_logger: BuildLogger = step.build_logger
|
|
21
|
+
build_logger.error(
|
|
22
|
+
"Build failed with Exception. See the stack trace above."
|
|
23
|
+
)
|
|
24
|
+
cleaning_up_after_build(step)
|
|
25
|
+
raise e
|
|
26
|
+
|
|
27
|
+
return inner_function
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def build_failure_handler():
|
|
31
|
+
def _exception_handler(func):
|
|
32
|
+
@wraps(func)
|
|
33
|
+
def inner_function(*args, **kwargs):
|
|
34
|
+
try:
|
|
35
|
+
func(*args, **kwargs)
|
|
36
|
+
except BaseException as e:
|
|
37
|
+
if not isinstance(e, QuietError):
|
|
38
|
+
build_logger: BuildLogger = args[0].build_logger
|
|
39
|
+
build_logger.error(
|
|
40
|
+
"Build failed with Exception. See the stack trace above."
|
|
41
|
+
)
|
|
42
|
+
cleaning_up_after_build(args[0])
|
|
43
|
+
raise e
|
|
44
|
+
return inner_function
|
|
45
|
+
|
|
46
|
+
return _exception_handler
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def cleaning_up_after_build(step: Step):
|
|
50
|
+
if os.getenv("QWAK_DEBUG") != "true":
|
|
51
|
+
step.build_logger.debug("Removing Qwak temp artifacts directory")
|
|
52
|
+
shutil.rmtree(step.context.host_temp_local_build_dir, ignore_errors=True)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def add_decorator_to_steps(phase_steps: List[Step]):
|
|
56
|
+
for step in phase_steps:
|
|
57
|
+
if not hasattr(step.execute, '__wrapped__'):
|
|
58
|
+
step_exception_handler_decorator(step)
|
|
59
|
+
|
|
60
|
+
return phase_steps
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from logging import Logger
|
|
2
|
+
import time
|
|
3
|
+
from typing import List
|
|
4
|
+
from _qwak_proto.qwak.build.v1.build_pb2 import BuildStatus
|
|
5
|
+
from qwak.clients.build_orchestrator import BuildOrchestratorClient
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def __get_current_status(build_id) -> BuildStatus:
|
|
9
|
+
return BuildOrchestratorClient().get_build(build_id).build.build_status
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def __end_state_statuses() -> List[BuildStatus.ValueType]:
|
|
13
|
+
return [BuildStatus.FAILED, BuildStatus.SUCCESSFUL, BuildStatus.REMOTE_BUILD_CANCELLED, BuildStatus.REMOTE_BUILD_TIMED_OUT, BuildStatus.FAILED_INITIATING_BUILD]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def wait_until_finished(build_id, log: Logger, pool_interval_seconds=10) -> None:
|
|
17
|
+
status = __get_current_status(build_id)
|
|
18
|
+
log.info(f"Waiting for build {build_id} to finish. Aborting this process will not stop the build!")
|
|
19
|
+
log.debug(f"Current status of build {build_id}: {BuildStatus.DESCRIPTOR.values_by_number[status].name}")
|
|
20
|
+
while status not in __end_state_statuses():
|
|
21
|
+
time.sleep(pool_interval_seconds)
|
|
22
|
+
status = __get_current_status(build_id)
|
|
23
|
+
log.debug(f"Current status of build {build_id}: {BuildStatus.DESCRIPTOR.values_by_number[status].name}")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def is_final_status_successful(build_id) -> bool:
|
|
27
|
+
return __get_current_status(build_id) == BuildStatus.SUCCESSFUL
|