def get_credentials(self): """Retrieve the credentials for the RemoteCompute target. :return: The credentials for the RemoteCompute target. :rtype: dict :raises azureml.exceptions.ComputeTargetException: """ endpoint = self._mlc_endpoint + '/listKeys' headers = self._auth.get_authentication_header() ComputeTarget._add_request_tracking_headers(headers) params = {'api-version': MLC_WORKSPACE_API_VERSION} resp = ClientBase._execute_func(get_requests_session().post, endpoint, params=params, headers=headers) try: resp.raise_for_status() except requests.exceptions.HTTPError: raise ComputeTargetException('Received bad response from MLC:\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') creds_content = json.loads(content) return creds_content
def _delete_or_detach(self, underlying_resource_action): """Remove the Compute object from its associated workspace. If underlying_resource_action is 'delete', the corresponding cloud-based objects will also be deleted. If underlying_resource_action is 'detach', no underlying cloud object will be deleted, the association will just be removed. :param underlying_resource_action: whether delete or detach the underlying cloud object :type underlying_resource_action: str :raises azureml.exceptions.ComputeTargetException: """ headers = self._auth.get_authentication_header() ComputeTarget._add_request_tracking_headers(headers) params = {'api-version': MLC_WORKSPACE_API_VERSION, 'underlyingResourceAction': underlying_resource_action} resp = ClientBase._execute_func(get_requests_session().delete, self._mlc_endpoint, params=params, headers=headers) try: resp.raise_for_status() except requests.exceptions.HTTPError: raise ComputeTargetException('Received bad response from Resource Provider:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format(resp.status_code, resp.headers, resp.content)) self.provisioning_state = 'Deleting' self._operation_endpoint = resp.headers['Azure-AsyncOperation']
def _get(workspace, name): """Return web response content for the compute. :param workspace: :type workspace: azureml.core.Workspace :param name: :type name: str :return: :rtype: dict """ endpoint = ComputeTarget._get_rp_compute_endpoint(workspace, name) headers = workspace._auth.get_authentication_header() ComputeTarget._add_request_tracking_headers(headers) params = {'api-version': MLC_WORKSPACE_API_VERSION} resp = ClientBase._execute_func(get_requests_session().get, endpoint, params=params, headers=headers) if resp.status_code == 200: content = resp.content if isinstance(content, bytes): content = content.decode('utf-8') get_content = json.loads(content) return get_content elif resp.status_code == 404: return None else: raise ComputeTargetException('Received bad response from Resource Provider:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format(resp.status_code, resp.headers, resp.content))
def _get_operation_state(self): """Return operation state. :return: :rtype: (str, dict) """ headers = self._auth.get_authentication_header() ComputeTarget._add_request_tracking_headers(headers) params = {} # API version should not be appended for operation status URLs. # This is a bug fix for older SDK and ARM breaking changes and # will append version only if the request URL doesn't have one. if 'api-version' not in self._operation_endpoint: params = {'api-version': MLC_WORKSPACE_API_VERSION} resp = ClientBase._execute_func(get_requests_session().get, self._operation_endpoint, params=params, headers=headers) try: resp.raise_for_status() except requests.exceptions.HTTPError: raise ComputeTargetException('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) status = content['status'] error = content.get('error') # Prior to API version 2019-06-01 the 'error' element was double nested. # This change retains backwards compat for 2018-11-19 version. if error is not None: innererror = error.get('error') if innererror is not None: error = innererror # --------------------------------------------------------------------- return status, error
def _attach(workspace, name, attach_payload, target_class): """Attach implementation method. :param workspace: :type workspace: azureml.core.Workspace :param name: :type name: str :param attach_payload: :type attach_payload: dict :param target_class: :type target_class: :return: :rtype: """ attach_payload['location'] = workspace.location endpoint = ComputeTarget._get_compute_endpoint(workspace, name) headers = {'Content-Type': 'application/json'} headers.update(workspace._auth.get_authentication_header()) ComputeTarget._add_request_tracking_headers(headers) params = {'api-version': MLC_WORKSPACE_API_VERSION} resp = ClientBase._execute_func(get_requests_session().put, endpoint, params=params, headers=headers, json=attach_payload) try: resp.raise_for_status() except requests.exceptions.HTTPError: raise ComputeTargetException('Received bad response from Resource Provider:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format(resp.status_code, resp.headers, resp.content)) if 'Azure-AsyncOperation' not in resp.headers: raise ComputeTargetException('Error, missing operation location from resp headers:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format(resp.status_code, resp.headers, resp.content)) compute_target = target_class(workspace, name) compute_target._operation_endpoint = resp.headers['Azure-AsyncOperation'] return compute_target
def list(workspace): """List all ComputeTarget objects within the workspace. Return a list of instantiated child objects corresponding to the specific type of Compute. Objects are children of :class:`azureml.core.ComputeTarget`. :param workspace: The workspace object containing the objects to list. :type workspace: azureml.core.Workspace :return: List of compute targets within the workspace. :rtype: builtin.list[azureml.core.ComputeTarget] :raises azureml.exceptions.ComputeTargetException: """ envs = [] endpoint = ComputeTarget._get_rp_list_computes_endpoint(workspace) headers = workspace._auth.get_authentication_header() ComputeTarget._add_request_tracking_headers(headers) params = {'api-version': MLC_WORKSPACE_API_VERSION} resp = ClientBase._execute_func(get_requests_session().get, endpoint, params=params, headers=headers) try: resp.raise_for_status() except requests.exceptions.HTTPError: raise ComputeTargetException('Error occurred retrieving targets:\n' 'Response Code: {}\n' 'Headers: {}\n' 'Content: {}'.format(resp.status_code, resp.headers, resp.content)) is_windows_contrib_installed = True try: from azureml.contrib.compute import AmlWindowsCompute # noqa: F401 except ImportError: is_windows_contrib_installed = False pass content = resp.content if isinstance(content, bytes): content = content.decode('utf-8') result_list = json.loads(content) paginated_results = get_paginated_compute_results(result_list, headers) for env in paginated_results: if 'properties' in env and 'computeType' in env['properties']: compute_type = env['properties']['computeType'] is_attached = env['properties']['isAttachedCompute'] env_obj = None for child in ComputeTarget.__subclasses__(): if is_attached and compute_type == 'VirtualMachine' and child.__name__ == 'DsvmCompute': # Cannot attach DsvmCompute continue elif not is_attached and compute_type == 'VirtualMachine' and child.__name__ == 'RemoteCompute': # Cannot create RemoteCompute continue elif not is_attached and compute_type == 'Kubernetes' and child.__name__ == 'KubernetesCompute': # Cannot create KubernetesCompute continue elif compute_type == child._compute_type: # If windows contrib is not installed, don't list windows compute type # Windows is currently supported only for RL runs. # The windows contrib is installed as a part of RL SDK install. # This step is trying to avoid users using this compute target by mistake for a non-RL run if not is_windows_contrib_installed and "properties" in env['properties'] and \ env['properties']['properties'] is not None and \ "osType" in env['properties']['properties'] and \ env['properties']['properties']['osType'].lower() == 'windows': pass else: env_obj = child.deserialize(workspace, env) break if env_obj: envs.append(env_obj) return envs