def _add_base_image_to_payload(self, json_payload): if self.base_image: if not self.runtime.lower( ) in CUSTOM_BASE_IMAGE_SUPPORTED_RUNTIMES.keys(): runtimes = '|'.join( CUSTOM_BASE_IMAGE_SUPPORTED_RUNTIMES.keys()) raise WebserviceException( 'Custom base image is not supported for {} run time. ' 'Supported runtimes are: {}'.format( self.runtime, runtimes), logger=module_logger) json_payload['baseImage'] = self.base_image json_payload['targetRuntime'][ 'runtimeType'] = CUSTOM_BASE_IMAGE_SUPPORTED_RUNTIMES[ self.runtime.lower()] if self.base_image_registry is not None: if self.base_image_registry.address and \ self.base_image_registry.username and \ self.base_image_registry.password: json_payload['baseImageRegistryInfo'] = { 'location': self.base_image_registry.address, 'user': self.base_image_registry.username, 'password': self.base_image_registry.password } elif self.base_image_registry.address or \ self.base_image_registry.username or \ self.base_image_registry.password: raise WebserviceException( 'Address, Username and Password ' 'must be provided for base image registry', logger=module_logger)
def convert_model(self, request): """ :param request: :type request: ModelConvertRequest :return: submit model conversion and return opertion id :rtype: str """ headers = {'Content-Type': 'application/json'} headers.update(self._workspace._auth.get_authentication_header()) params = {'api-version': MMS_WORKSPACE_API_VERSION} if request.model_id: model_endpoint = self._mms_endpoint + '/models' + '/{}/convert'.format( request.model_id) else: raise Exception( 'Model id is missing in the request {}.'.format(request)) json_payload = json.loads(request.toJSON()) try: resp = requests.post(model_endpoint, params=params, headers=headers, json=json_payload) resp.raise_for_status() except requests.ConnectionError: raise Exception('Error connecting to {}.'.format(model_endpoint)) except requests.exceptions.HTTPError: raise Exception( 'Received bad response from Model Management Service:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format(resp.status_code, resp.headers, resp.content)) if resp.status_code != 202: raise WebserviceException('Error occurred converting model:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format( resp.status_code, resp.headers, resp.content)) if 'Operation-Location' in resp.headers: operation_location = resp.headers['Operation-Location'] else: raise WebserviceException( 'Missing response header key: Operation-Location') operation_status_id = operation_location.split('/')[-1] return operation_status_id
def get_operation_state(self, operation_id): """ :param operation_id: :type operation_id: str :return: operation state, operation content :rtype: (str, object) """ headers = {'Content-Type': 'application/json'} headers.update(self._workspace._auth.get_authentication_header()) params = {'api-version': MMS_WORKSPACE_API_VERSION} operation_endpoint = self._mms_endpoint + '/operations/{}'.format( operation_id) resp = requests.get(operation_endpoint, headers=headers, params=params, timeout=MMS_SYNC_TIMEOUT_SECONDS) try: resp.raise_for_status() except requests.exceptions.HTTPError: raise WebserviceException( 'Received bad response from Resource Provider:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format(resp.status_code, resp.headers, resp.content)) content = resp.content if isinstance(content, bytes): content = content.decode('utf-8') content = json.loads(content) state = content['state'] return state, content
def update(self, tags): """Update the image. :param tags: A dictionary of tags to update the image with. Will overwrite any existing tags. :type tags: dict[str, str] :raises: azureml.exceptions.WebserviceException """ headers = {'Content-Type': 'application/json-patch+json'} headers.update(self._auth.get_authentication_header()) params = {} patch_list = [] self.tags = tags patch_list.append({ 'op': 'replace', 'path': '/kvTags', 'value': self.tags }) resp = ClientBase._execute_func(get_requests_session().patch, self._mms_endpoint, headers=headers, params=params, json=patch_list, timeout=MMS_SYNC_TIMEOUT_SECONDS) if resp.status_code >= 400: raise WebserviceException( 'Received bad response from Model Management Service:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format(resp.status_code, resp.headers, resp.content), logger=module_logger)
def model_error_response_to_webservice_exception(ex, **kwargs): if not isinstance(ex, ModelErrorResponseException): raise WebserviceException( 'Received unexpected exception: {}'.format(ex), logger=module_logger) if ex.error.status_code == 404: error_message = populate_model_not_found_details(**kwargs) raise WebserviceException(error_message, logger=module_logger) raise WebserviceException( 'Received bad response from Model Management Service:\n' 'Response Code: {}\n' 'Correlation: {}\n' 'Content: {}'.format(ex.error.status_code, ex.error.correlation, ex.error.details), logger=module_logger)
def _extract_credentials(registry_dict): try: username = registry_dict["containerRegistryCredentials"]["username"] passwords = registry_dict["containerRegistryCredentials"]["passwords"] password = passwords[0]["value"] except KeyError: raise WebserviceException( "Unable to retrieve workspace keys to run image, response " "payload missing container registry credentials.") return username, password
def wait_for_creation(self, show_output=False): """Wait for the image to finish creating. Wait for image creation to reach a terminal state. Will throw a WebserviceException if it reaches a non-successful terminal state. :param show_output: Boolean option to print more verbose output. Defaults to False. :type show_output: bool :raises: azureml.exceptions.WebserviceException """ operation_state, error = self._get_operation_state() current_state = operation_state if show_output: sys.stdout.write('{}'.format(current_state)) sys.stdout.flush() while operation_state != 'Cancelled' and operation_state != 'Succeeded' and operation_state != 'Failed' \ and operation_state != 'TimedOut': time.sleep(5) operation_state, error = self._get_operation_state() if show_output: sys.stdout.write('.') if operation_state != current_state: sys.stdout.write('\n{}'.format(operation_state)) current_state = operation_state sys.stdout.flush() sys.stdout.write('\n') sys.stdout.flush() self.update_creation_state() if operation_state != 'Succeeded': if error and 'statusCode' in error and 'message' in error: error_response = ('StatusCode: {}\n' 'Message: {}'.format(error['statusCode'], error['message'])) else: error_response = error print( 'More information about this error is available here: {}\n' 'For more help with troubleshooting, see https://aka.ms/debugimage' .format(self.image_build_log_uri)) raise WebserviceException( 'Image creation polling reached non-successful terminal state, ' 'current state: {}\n' 'Error response from server:\n' '{}'.format(self.creation_state, error_response), logger=module_logger) print('Image creation operation finished for image {}, operation "{}"'. format(self.id, operation_state))
def update_creation_state(self): """Refresh the current state of the in-memory object. Perform an in-place update of the properties of the object based on the current state of the corresponding cloud object. Primarily useful for manual polling of creation state. :raises: azureml.exceptions.WebserviceException """ headers = {'Content-Type': 'application/json'} headers.update(self._auth.get_authentication_header()) params = {} resp = ClientBase._execute_func(get_requests_session().get, self._mms_endpoint, headers=headers, params=params, timeout=MMS_SYNC_TIMEOUT_SECONDS) if resp.status_code == 200: image = Image(self.workspace, id=self.id) for key in image.__dict__.keys(): if key is not "_operation_endpoint": self.__dict__[key] = image.__dict__[key] elif resp.status_code == 404: raise WebserviceException('Error: image {} not found:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format( self.id, resp.status_code, resp.headers, resp.content), logger=module_logger) else: raise WebserviceException( 'Received bad response from Model Management Service:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format(resp.status_code, resp.headers, resp.content), logger=module_logger)
def _get_operation_state(self): """Get the current async operation state for the image. :return: :rtype: (str, dict) """ if not self._operation_endpoint: self.update_deployment_state() raise WebserviceException( 'Long running operation information not known, unable to poll. ' 'Current state is {}'.format(self.creation_state), logger=module_logger) headers = {'Content-Type': 'application/json'} headers.update(self._auth.get_authentication_header()) params = {} resp = ClientBase._execute_func(get_requests_session().get, self._operation_endpoint, headers=headers, params=params, timeout=MMS_SYNC_TIMEOUT_SECONDS) try: resp.raise_for_status() except requests.exceptions.HTTPError: raise WebserviceException( 'Received bad response from Resource Provider:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format(resp.status_code, resp.headers, resp.content), logger=module_logger) content = resp.content if isinstance(content, bytes): content = content.decode('utf-8') content = json.loads(content) state = content['state'] error = content['error'] if 'error' in content else None return state, error
def _validate_get_payload(cls, payload): """Validate the returned _ModelEvaluationResultBase payload. :param payload: :type payload: dict :return: :rtype: None """ for payload_key in cls._expected_payload_keys: if payload_key not in payload: raise WebserviceException( 'Invalid payload for %s, missing %s:\n %s' % (cls._model_eval_type, payload_key, payload) )
def _validate_get_payload(cls, payload): """Validate the returned image payload. :param payload: :type payload: dict :return: :rtype: None """ for payload_key in cls._expected_payload_keys: if payload_key not in payload: raise WebserviceException( 'Invalid image payload, missing {} for image:\n' '{}'.format(payload_key, payload), logger=module_logger)
def create_local_debug_payload(self, workspace, model_ids): """ Build the creation payload for the Container image. :param workspace: The workspace object to create the image in. :type workspace: azureml.core.Workspace :param model_ids: A list of model IDs to package into the image. :type model_ids: builtin.list[str] :return: Container image creation payload. :rtype: dict :raises: azureml.exceptions.WebserviceException """ import copy from azureml._model_management._util import image_payload_template json_payload = copy.deepcopy(image_payload_template) json_payload['name'] = 'local' json_payload['kvTags'] = self.tags json_payload['imageFlavor'] = WEBAPI_IMAGE_FLAVOR json_payload['properties'] = self.properties json_payload['description'] = self.description json_payload['targetRuntime']['runtimeType'] = SUPPORTED_RUNTIMES[ self.runtime.lower()] json_payload['targetRuntime'][ 'targetArchitecture'] = ARCHITECTURE_AMD64 if self.enable_gpu or self.cuda_version: raise WebserviceException('Local web services do not support GPUs', logger=module_logger) json_payload['targetRuntime']['properties'][ 'pipRequirements'] = "requirements.txt" if self.docker_file: docker_file = self.docker_file.rstrip(os.sep) (json_payload['dockerFileUri'], _) = upload_dependency(workspace, docker_file) if self.conda_file: conda_file = self.conda_file.rstrip(os.sep) json_payload['targetRuntime']['properties'][ 'condaEnvFile'] = os.path.basename(conda_file) if model_ids: json_payload['modelIds'] = model_ids self._add_base_image_to_payload(json_payload) return json_payload
def delete(self): """Delete an image from its corresponding workspace. .. remarks:: This method fails if the image has been deployed to a live webservice. :raises: azureml.exceptions.WebserviceException """ headers = self._auth.get_authentication_header() params = {} resp = ClientBase._execute_func(get_requests_session().delete, self._mms_endpoint, headers=headers, params=params, timeout=MMS_SYNC_TIMEOUT_SECONDS) if resp.status_code >= 400: if resp.status_code == 412 and "DeletionRequired" in resp.content: raise WebserviceException( 'The image cannot be deleted because it is currently being used in one or ' 'more webservices. To know what webservices contain the image, run ' '"Webservice.list(<workspace>, image_id={})"'.format( self.id), logger=module_logger) raise WebserviceException( 'Received bad response from Model Management Service:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format(resp.status_code, resp.headers, resp.content), logger=module_logger) else: self.creation_state = 'Deleting'
def deserialize(payload_obj): """Convert a JSON object into a ResourceConfiguration object. :param payload_obj: A JSON object to convert to a ResourceConfiguration object. :type payload_obj: dict :return: The ResourceConfiguration representation of the provided JSON object. :rtype: azureml.core.resource_configuration.ResourceConfiguration """ if payload_obj is None: return None for payload_key in ResourceConfiguration._expected_payload_keys: if payload_key not in payload_obj: raise WebserviceException('Invalid webservice payload, missing {} for ResourceConfiguration:\n' '{}'.format(payload_key, payload_obj), logger=module_logger) return ResourceConfiguration(payload_obj['cpu'], payload_obj['memoryInGB'], payload_obj['gpu'])
def remove_tags(self, tags): """Remove tags from the image. :param tags: A list of keys corresponding to tags to be removed. :type tags: builtin.list[str] :raises: azureml.exceptions.WebserviceException """ headers = {'Content-Type': 'application/json-patch+json'} headers.update(self._auth.get_authentication_header()) params = {} patch_list = [] if self.tags is None: print('Image has no tags to remove.') return else: if type(tags) is not list: tags = [tags] for key in tags: if key in self.tags: del self.tags[key] else: print('Tag with key {} not found.'.format(key)) patch_list.append({ 'op': 'replace', 'path': '/kvTags', 'value': self.tags }) resp = ClientBase._execute_func(get_requests_session().patch, self._mms_endpoint, headers=headers, params=params, json=patch_list, timeout=MMS_SYNC_TIMEOUT_SECONDS) if resp.status_code >= 400: raise WebserviceException( 'Received bad response from Model Management Service:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format(resp.status_code, resp.headers, resp.content), logger=module_logger) print('Image tag remove operation complete.')
def _validate_configuration(self): """Check that the specified configuration values are valid. Will raise a :class:`azureml.exceptions.WebserviceException` if validation fails. :raises: azureml.exceptions.WebserviceException """ error = "" if self.cpu and self.cpu <= 0: error += 'Invalid configuration, cpu must be greater than zero.\n' if self.memory_in_gb and self.memory_in_gb <= 0: error += 'Invalid configuration, memory_in_gb must be greater than zero.\n' if self.gpu and not isinstance(self.gpu, int) and self.gpu <= 0: error += 'Invalid configuration, gpu must be integer and greater than zero.\n' if error: raise WebserviceException(error, logger=module_logger)
def diagnostics(self, uri): """ Retrieves the diagnostics in the working directory of the current run. """ auth = self.run._service_context.get_auth() headers = auth.get_authentication_header() with create_session_with_retry() as session: try: response = ClientBase._execute_func(session.get, uri, headers=headers) response.raise_for_status() except requests.exceptions.HTTPError: raise WebserviceException('Received bad response from Execution Service:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format(response.status_code, response.headers, response.content), logger=module_logger) return response
def deserialize(payload_obj): """Convert a JSON object into an Asset object. :param payload_obj: A JSON object to convert to an Asset object. :type payload_obj: dict :return: The Asset representation of the provided JSON object. :rtype: Asset :raises: azureml.exceptions.WebserviceException """ for payload_key in Asset._expected_payload_keys: if payload_key not in payload_obj: raise WebserviceException( 'Invalid image payload, missing {} for asset:\n' '{}'.format(payload_key, payload_obj), logger=module_logger) return Asset(payload_obj['id'], payload_obj['mimeType'], payload_obj['unpack'], payload_obj['url'])
def run(self, input_data): """ Run the image locally with the given input data. Must have Docker installed and running to work. This method will only work on CPU, as the GPU-enabled image can only run on Microsoft Azure Services. :param input_data: The input data to pass to the image when run :type input_data: varies :return: The results of running the image. :rtype: varies :raises: azureml.exceptions.WebserviceException """ if not input_data: raise WebserviceException('Error: You must provide input data.', logger=module_logger) username, password = get_workspace_registry_credentials(self.workspace) client = get_docker_client() login_to_docker_registry(client, username, password, self.image_location) pull_docker_image(client, self.image_location, username, password) ports = { DOCKER_IMAGE_HTTP_PORT: ('127.0.0.1', None) } # None assigns a random free port. container_name = self.id + str(uuid.uuid4())[:8] container = run_docker_container(client, self.image_location, container_name, ports=ports) docker_port = get_docker_port(client, container_name, container) docker_url = container_health_check(docker_port, container) scoring_result = container_scoring_call(docker_port, input_data, container, docker_url) cleanup_container(container) return scoring_result
def add_tags(self, tags): """Add tags to the image. :param tags: A dictionary of tags to add. :type tags: dict[str, str] :raises: azureml.exceptions.WebserviceException """ headers = {'Content-Type': 'application/json-patch+json'} headers.update(self._auth.get_authentication_header()) params = {} patch_list = [] if self.tags is None: self.tags = copy.deepcopy(tags) else: for key in tags: if key in self.tags: print("Replacing tag {} -> {} with {} -> {}".format( key, self.tags[key], key, tags[key])) self.tags[key] = tags[key] patch_list.append({ 'op': 'replace', 'path': '/kvTags', 'value': self.tags }) resp = ClientBase._execute_func(get_requests_session().patch, self._mms_endpoint, headers=headers, params=params, json=patch_list, timeout=MMS_SYNC_TIMEOUT_SECONDS) if resp.status_code >= 400: raise WebserviceException( 'Received bad response from Model Management Service:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format(resp.status_code, resp.headers, resp.content), logger=module_logger) print('Image tag add operation complete.')
def add_properties(self, properties): """Add properties to the image. :param properties: A dictionary of properties to add. :type properties: dict[str, str] :raises: azureml.exceptions.WebserviceException """ check_duplicate_properties(self.properties, properties) headers = {'Content-Type': 'application/json-patch+json'} headers.update(self._auth.get_authentication_header()) params = {} patch_list = [] if self.properties is None: self.properties = copy.deepcopy(properties) else: for key in properties: self.properties[key] = properties[key] patch_list.append({ 'op': 'add', 'path': '/properties', 'value': self.properties }) resp = ClientBase._execute_func(get_requests_session().patch, self._mms_endpoint, headers=headers, params=params, json=patch_list, timeout=MMS_SYNC_TIMEOUT_SECONDS) if resp.status_code >= 400: raise WebserviceException( 'Received bad response from Model Management Service:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format(resp.status_code, resp.headers, resp.content), logger=module_logger) print('Image properties add operation complete.')
def file_stream_to_object(file_stream): """ Take a YAML or JSON file_stream and return the dictionary object. :param file_stream: File stream from with open(file) as file_stream :type file_stream: :return: File dictionary :rtype: dict """ file_data = file_stream.read() try: return yaml.safe_load(file_data) except Exception as ex: pass try: return json.loads(file_data) except Exception as ex: raise WebserviceException('Error while parsing file. Must be valid JSON or YAML file.', content=ex)
def _update_creation_state(self): """Refresh the current state of the in-memory object. Perform an in-place update of the properties of the object based on the current state of the corresponding cloud object. Primarily useful for manual polling of creation state. :raises: azureml.exceptions.WebserviceException """ resp = get_operation_output(self.workspace, self._model_test_result_suffix, self._model_test_result_params) if resp.status_code != 200: error_message = 'Model {} result with name {}'.format( self.__class__._model_eval_type, self.name ) error_message += ' not found in provided workspace' raise WebserviceException(error_message) content = resp.content if isinstance(content, bytes): content = content.decode('utf-8') model_test_json = json.loads(content)['value'][0] self._validate_get_payload(model_test_json) self._initialize(model_test_json)
def deserialize(payload_obj): """Convert a JSON object into a ContainerResourceRequirements object. :param payload_obj: A JSON object to convert to a ContainerResourceRequirements object. :type payload_obj: dict :return: The ContainerResourceRequirements representation of the provided JSON object. :rtype: azureml.core.webservice.webservice.ContainerResourceRequirements """ for payload_key in ContainerResourceRequirements._expected_payload_keys: if payload_key not in payload_obj: raise WebserviceException( 'Invalid webservice payload, missing {} for ContainerResourceRequirements:\n' '{}'.format(payload_key, payload_obj), logger=module_logger) return ContainerResourceRequirements( cpu=payload_obj['cpu'], memory_in_gb=payload_obj['memoryInGB'], gpu=payload_obj['gpu'], cpu_limit=payload_obj['cpuLimit'], memory_in_gb_limit=payload_obj['memoryInGBLimit'])
def deserialize(payload_obj): """Convert a JSON object into a TargetRuntime object. :param payload_obj: A JSON object to convert to a TargetRuntime object. :type payload_obj: dict :return: The TargetRuntime representation of the provided JSON object. :rtype: TargetRuntime :raises: azureml.exceptions.WebserviceException """ for payload_key in TargetRuntime._expected_payload_keys: if payload_key not in payload_obj: raise WebserviceException( 'Invalid image payload, missing {} for targetRuntime:\n' '{}'.format(payload_key, payload_obj), logger=module_logger) targetArchitecture = ARCHITECTURE_AMD64 if 'targetArchitecture' in payload_obj: targetArchitecture = payload_obj['targetArchitecture'] return TargetRuntime(payload_obj['properties'], payload_obj['runtimeType'], targetArchitecture)
def _registry_dict_for(subscription_id, resource_group, workspace_name, authentication_header): keys_endpoint = _KEYS_URL.format(subscription_id, resource_group, workspace_name) # headers = self.workspace._auth.get_authentication_header() params = {"api-version": WORKSPACE_RP_API_VERSION} try: keys_resp = requests.post(keys_endpoint, headers=authentication_header, params=params) keys_resp.raise_for_status() except requests.exceptions.HTTPError: raise WebserviceException( "Unable to retrieve workspace keys to run image:\n" "Response Code: {}\n" "Headers: {}\n" "Content: {}".format(keys_resp.status_code, keys_resp.headers, keys_resp.content)) content = keys_resp.content if isinstance(content, bytes): content = content.decode("utf-8") return json.loads(content)
def result(self): """ If the model conversion completed return the converted model. :return: converted model if convert model operation succeeded. :rtype: azureml.core.model """ operation_state, content = self._client.get_operation_state( self._operation_id) if operation_state == 'Succeeded': if 'resourceLocation' in content: resource_location = content['resourceLocation'] model_id = resource_location.split('/')[-1] return Model(self._workspace, id=model_id) else: raise WebserviceException( 'Invalid operation payload, missing resourceLocation:\n' '{}'.format(resource_location)) elif operation_state == 'Cancelled' or operation_state == 'Failed' or operation_state == 'TimedOut': raise ValueError("Model conversion is not successful") else: raise ValueError("Model conversion is not complete")
def validate_configuration(self): """Check that the specified configuration values are valid. Raises a :class:azureml.exceptions.WebserviceException` if validation fails. :raises: azureml.exceptions.WebserviceException """ if self.allow_absolute_path is False: # The execution script must have a relative path if os.path.isabs(self.execution_script): raise WebserviceException( 'Unable to use absolute path for execution script. ' 'Use a relative path for execution script and try again.', logger=module_logger) # The execution script must be in the current directory if not os.getcwd() == self.execution_script_path: raise WebserviceException( 'Unable to use an execution script not in current directory. ' 'Please navigate to the location of the execution script and try again.', logger=module_logger) validate_path_exists_or_throw(self.execution_script, "Execution script") execution_script_name, execution_script_extension = os.path.splitext( os.path.basename(self.execution_script)) if execution_script_extension != '.py': raise WebserviceException( 'Invalid driver type. Currently only Python drivers are supported.', logger=module_logger) validate_entry_script_name(execution_script_name) if self.runtime.lower() not in SUPPORTED_RUNTIMES.keys(): runtimes = '|'.join(x for x in SUPPORTED_RUNTIMES.keys() if x not in UNDOCUMENTED_RUNTIMES) raise WebserviceException( 'Provided runtime not supported. ' 'Possible runtimes are: {}'.format(runtimes), logger=module_logger) if self.cuda_version is not None: if self.cuda_version.lower() not in SUPPORTED_CUDA_VERSIONS: cuda_versions = '|'.join(SUPPORTED_CUDA_VERSIONS) raise WebserviceException( 'Provided cuda_version not supported. ' 'Possible values are: {}'.format(cuda_versions), logger=module_logger) if self.conda_file: validate_path_exists_or_throw(self.conda_file, "Conda file") if self.docker_file: validate_path_exists_or_throw(self.docker_file, "Docker file") if self.dependencies: for dependency in self.dependencies: validate_path_exists_or_throw(dependency, "Dependency") if self.schema_file: validate_path_exists_or_throw(self.schema_file, "Schema file") schema_file_path = os.path.abspath( os.path.dirname(self.schema_file)) common_prefix = os.path.commonprefix( [self.execution_script_path, schema_file_path]) if not common_prefix == self.execution_script_path: raise WebserviceException( 'Schema file must be in the same directory as the execution script, ' 'or in a subdirectory.', logger=module_logger)
def submit_update_call(service, models, inference_config, deploy_config, aks_endpoint_version_config): if service._webservice_type.lower() == ACI_WEBSERVICE_TYPE.lower(): # aci update service.update(auth_enabled=deploy_config.auth_enabled, ssl_enabled=deploy_config.ssl_enabled, ssl_cert_pem_file=deploy_config.ssl_cert_pem_file, ssl_key_pem_file=deploy_config.ssl_key_pem_file, ssl_cname=deploy_config.ssl_cname, enable_app_insights=deploy_config.enable_app_insights, models=models, inference_config=inference_config) elif service._webservice_type.lower() == AKS_WEBSERVICE_TYPE.lower(): # aks update service.update(autoscale_enabled=deploy_config.autoscale_enabled, autoscale_min_replicas=deploy_config.autoscale_min_replicas, autoscale_max_replicas=deploy_config.autoscale_max_replicas, autoscale_refresh_seconds=deploy_config.autoscale_refresh_seconds, autoscale_target_utilization=deploy_config.autoscale_target_utilization, collect_model_data=deploy_config.collect_model_data, auth_enabled=deploy_config.auth_enabled, cpu_cores=deploy_config.cpu_cores, memory_gb=deploy_config.memory_gb, enable_app_insights=deploy_config.enable_app_insights, scoring_timeout_ms=deploy_config.scoring_timeout_ms, replica_max_concurrent_requests=deploy_config.replica_max_concurrent_requests, max_request_wait_time=deploy_config.max_request_wait_time, num_replicas=deploy_config.num_replicas, token_auth_enabled=deploy_config.token_auth_enabled, models=models, inference_config=inference_config, cpu_cores_limit=deploy_config.cpu_cores_limit, memory_gb_limit=deploy_config.memory_gb_limit) elif service._webservice_type.lower() == AKS_ENDPOINT_TYPE.lower(): # aksendpoint update if aks_endpoint_version_config and aks_endpoint_version_config['version_operation_type'] is not None: version_operation_type = aks_endpoint_version_config['version_operation_type'].lower() is_default = aks_endpoint_version_config['is_default'] is_control_version_type = aks_endpoint_version_config['is_control_version'] if version_operation_type == AKS_ENDPOINT_CREATE_VERSION.lower(): service.create_version( version_name=deploy_config.version_name, autoscale_enabled=deploy_config.autoscale_enabled, autoscale_min_replicas=deploy_config.autoscale_min_replicas, autoscale_max_replicas=deploy_config.autoscale_max_replicas, autoscale_refresh_seconds=deploy_config.autoscale_refresh_seconds, autoscale_target_utilization=deploy_config.autoscale_target_utilization, collect_model_data=deploy_config.collect_model_data, cpu_cores=deploy_config.cpu_cores, memory_gb=deploy_config.memory_gb, scoring_timeout_ms=deploy_config.scoring_timeout_ms, replica_max_concurrent_requests=deploy_config.replica_max_concurrent_requests, max_request_wait_time=deploy_config.max_request_wait_time, num_replicas=deploy_config.num_replicas, models=models, inference_config=inference_config, gpu_cores=deploy_config.gpu_cores, period_seconds=deploy_config.period_seconds, initial_delay_seconds=deploy_config.initial_delay_seconds, timeout_seconds=deploy_config.timeout_seconds, success_threshold=deploy_config.success_threshold, failure_threshold=deploy_config.failure_threshold, traffic_percentile=deploy_config.traffic_percentile, is_default=is_default, is_control_version_type=is_control_version_type, cpu_cores_limit=deploy_config.cpu_cores_limit, memory_gb_limit=deploy_config.memory_gb_limit) elif version_operation_type == AKS_ENDPOINT_DELETE_VERSION.lower(): service.delete_version(version_name=deploy_config.version_name) elif version_operation_type == AKS_ENDPOINT_UPDATE_VERSION.lower(): service.update_version( version_name=deploy_config.version_name, autoscale_enabled=deploy_config.autoscale_enabled, autoscale_min_replicas=deploy_config.autoscale_min_replicas, autoscale_max_replicas=deploy_config.autoscale_max_replicas, autoscale_refresh_seconds=deploy_config.autoscale_refresh_seconds, autoscale_target_utilization=deploy_config.autoscale_target_utilization, collect_model_data=deploy_config.collect_model_data, cpu_cores=deploy_config.cpu_cores, memory_gb=deploy_config.memory_gb, scoring_timeout_ms=deploy_config.scoring_timeout_ms, replica_max_concurrent_requests=deploy_config.replica_max_concurrent_requests, max_request_wait_time=deploy_config.max_request_wait_time, num_replicas=deploy_config.num_replicas, models=models, inference_config=inference_config, gpu_cores=deploy_config.gpu_cores, period_seconds=deploy_config.period_seconds, initial_delay_seconds=deploy_config.initial_delay_seconds, timeout_seconds=deploy_config.timeout_seconds, success_threshold=deploy_config.success_threshold, failure_threshold=deploy_config.failure_threshold, traffic_percentile=deploy_config.traffic_percentile, is_default=is_default, is_control_version_type=is_control_version_type, cpu_cores_limit=deploy_config.cpu_cores_limit, memory_gb_limit=deploy_config.memory_gb_limit) else: service.update(auth_enabled=deploy_config.auth_enabled, token_auth_enabled=deploy_config.token_auth_enabled, enable_app_insights=deploy_config.enable_app_insights) elif service._webservice_type.lower() == 'local': # local update deployment_config = \ LocalWebservice.deploy_configuration(port=deploy_config.port if deploy_config else None) service.update(models=models, deployment_config=deployment_config, inference_config=inference_config) else: raise WebserviceException("Unknown deployment type: {}".format(service._webservice_type))
print("Attempting to deploy model to web service") # Deploy this particular web service to your AKS cluster. service = Model.deploy(workspace=ws, name=web_service_name, models=[model], inference_config=inf_config, deployment_config=aks_config, deployment_target=aks_target, overwrite=True) print("Waiting for deployment to complete:") try: service.wait_for_deployment() print('Deployed AKS Webservice: {} \nWebservice Uri: {}'.format( service.name, service.scoring_uri)) except: print(service.get_logs()) try: service_key = service.get_keys()[0] except WebserviceException as e: raise WebserviceException( 'Error attempting to retrieve service keys for use with scoring:\n{}' .format(e.message)) web_service_details = {} web_service_details['service_name'] = service.name web_service_details['service_url'] = service.scoring_uri web_service_details["key"] = service_key with open('./service_details.json', 'w') as outfile: json.dump(obj=web_service_details, fp=outfile)