ScriptExecutor class to execute Python scripts
| 55 | |
| 56 | |
| 57 | class PythonScriptExecutor(ScriptExecutor): |
| 58 | """ |
| 59 | ScriptExecutor class to execute Python scripts |
| 60 | """ |
| 61 | EXTENSION = ".py" |
| 62 | PIP_PACKAGE_NAME = "pip" |
| 63 | UPLOAD_STATE_CHECK_INTERVAL_SECONDS = 20 |
| 64 | CUSTOM_PIP_PATH = os.path.join(utils.RESOURCES_DIRECTORY, PIP_PACKAGE_NAME) |
| 65 | DUMMY_WHL_PATH = os.path.join(utils.RESOURCES_DIRECTORY, "random_whl-0.0.1-py3-none-any.whl") |
| 66 | |
| 67 | def __init__(self, automation_session: AzureAutomationSession, script_path: str, requirements_file: str = None) -> None: |
| 68 | """ |
| 69 | :param automation_session: Automation account session to use |
| 70 | :param script_path: Script to execute within Automation Account |
| 71 | :param requirements_path: Path to requirements file to be installed and use by the script |
| 72 | """ |
| 73 | super().__init__(automation_session, script_path) |
| 74 | self.requirements_file = requirements_file |
| 75 | |
| 76 | def _delete_pip_if_exists(self): |
| 77 | """ |
| 78 | Validate 'pip' package does not exist |
| 79 | |
| 80 | :param delete_if_exists: If True and package exists, deletes the package |
| 81 | |
| 82 | :raises CloudMinerException: If package exists and 'delete_if_exists' is False |
| 83 | """ |
| 84 | pip_package = self.automation_session.get_python_package(PythonScriptExecutor.PIP_PACKAGE_NAME) |
| 85 | if pip_package: |
| 86 | logger.warning(f"Package '{PythonScriptExecutor.PIP_PACKAGE_NAME}' already exists in Automation Account. Deleting package") |
| 87 | self.automation_session.delete_python_package(PythonScriptExecutor.PIP_PACKAGE_NAME) |
| 88 | |
| 89 | def _wait_for_package_upload(self, package_name: str, timeout_seconds: int = UPLOAD_TIMEOUT): |
| 90 | """ |
| 91 | Wait until the package upload flow is finished or until timeout (Blocking) |
| 92 | |
| 93 | :param package_name: Python package name to wait for |
| 94 | :param timeout_seconds: Maximum time to wait for the upload |
| 95 | |
| 96 | :raises CloudMinerException: If the upload flow has not started for the given package |
| 97 | If upload flow has finished with an error |
| 98 | If timeout is reached |
| 99 | """ |
| 100 | logger.info(f"Waiting for package to finish upload. This might take a few minutes...") |
| 101 | logger.add_indent() |
| 102 | start_time = time.time() |
| 103 | end_time = start_time + timeout_seconds |
| 104 | while time.time() < end_time: |
| 105 | package_data = self.automation_session.get_python_package(package_name) |
| 106 | if not package_data: |
| 107 | raise CloudMinerException(f"Upload flow for package '{package_name}' has failed to be started") |
| 108 | |
| 109 | upload_state = package_data["properties"]["provisioningState"] |
| 110 | if upload_state == UPLOAD_STATE.SUCCEEDED: |
| 111 | logger.remove_indent() |
| 112 | break |
| 113 | elif upload_state == UPLOAD_STATE.FAILED: |
| 114 | error = package_data["properties"]["error"]["message"] |