def create_endpoint(parameters: dict, namespace: str, id_token: str): if not tenant_exists(namespace, id_token=id_token): raise TenantDoesNotExistException(tenant_name=namespace) metadata = {"name": parameters['endpointName']} body = {"apiVersion": CRD_API_VERSION, "kind": CRD_KIND, "spec": parameters, "metadata": metadata} api_instance = get_k8s_api_client(id_token) if 'resources' in parameters: validate_quota_compliance(api_instance, namespace=namespace, endpoint_quota=parameters['resources']) parameters['resources'] = transform_quota(parameters['resources']) apps_api_instance = get_k8s_apps_api_client(id_token) verify_endpoint_amount(api_instance, apps_api_instance, namespace) custom_obj_api_instance = get_k8s_api_custom_client(id_token) try: custom_obj_api_instance.create_namespaced_custom_object(CRD_GROUP, CRD_VERSION, namespace, CRD_PLURAL, body) except ApiException as apiException: raise KubernetesCreateException('endpoint', apiException) endpoint_url = create_url_to_service(parameters['endpointName'], namespace) logger.info('Endpoint {} created\n'.format(endpoint_url)) return endpoint_url
def view_endpoint(endpoint_name: str, namespace: str, id_token: str): if not tenant_exists(namespace, id_token=id_token): raise TenantDoesNotExistException(tenant_name=namespace) if not endpoint_exists(endpoint_name, namespace, id_token): raise EndpointDoesNotExistException(endpoint_name=endpoint_name) custom_api_instance = get_k8s_api_custom_client(id_token) api_instance = get_k8s_api_client(id_token) apps_api_instance = get_k8s_apps_api_client(id_token) endpoint_status = get_endpoint_status(api_instance=api_instance, namespace=namespace, endpoint_name=endpoint_name) model_path = create_url_to_service(endpoint_name, namespace) subject_name, resources = get_crd_subject_name_and_resources( custom_api_instance=custom_api_instance, namespace=namespace, endpoint_name=endpoint_name) replicas = get_replicas(apps_api_instance=apps_api_instance, namespace=namespace, endpoint_name=endpoint_name) view_dict = {'Endpoint status': endpoint_status, 'Model path': model_path, 'Subject name': subject_name, 'Resources': resources, 'Replicas': replicas, } message = f"Endpoint {endpoint_name} in {namespace} tenant: {view_dict}\n" logger.info(message) return message
def delete_model(parameters: dict, namespace: str, id_token): if not tenant_exists(namespace, id_token): raise TenantDoesNotExistException(namespace) model_path = f"{parameters['modelName']}-{parameters['modelVersion']}" bucket = minio_resource.Bucket(name=namespace) model_in_bucket = bucket.objects.filter(Prefix=model_path) if not model_exists(model_in_bucket): raise ModelDoesNotExistException(model_path) apps_api_client = get_k8s_apps_api_client(id_token) try: deployments = apps_api_client.list_namespaced_deployment(namespace) except ApiException as apiException: raise KubernetesGetException('deployment', apiException) endpoint_names = endpoints_using_model(deployments, model_path) if endpoint_names: raise ModelDeleteException( f'model is used by endpoints: {endpoint_names}') for key in model_in_bucket: key.delete() return model_path
def on_put(self, req, resp, tenant_name): namespace = tenant_name multipart_id = req.get_param('uploadId') try: part_number = int(req.get_param('partNumber')) except (ValueError, TypeError): raise InvalidParamException('partNumber', 'Wrong partNumber parameter value') key = get_key(req.params) logger.info(f"Key: {key} ID: {multipart_id}") data = req.stream.read() if not tenant_exists(namespace, id_token=req.params['Authorization']): raise TenantDoesNotExistException(tenant_name=namespace) part_etag = upload_part(data=data, part_number=part_number, bucket=namespace, key=key, multipart_id=multipart_id) logger.info(f"ETag: {part_etag}") resp.status = falcon.HTTP_200 resp.body = json.dumps({ 'status': 'OK', 'data': { 'ETag': part_etag, 'op': 'upload_part' } })
def list_models(namespace: str, id_token): if not tenant_exists(namespace, id_token): raise TenantDoesNotExistException(namespace) apps_api_client = get_k8s_apps_api_client(id_token) try: deployments = apps_api_client.list_namespaced_deployment(namespace) except ApiException as apiException: raise KubernetesGetException('deployment', apiException) try: bucket = minio_resource.Bucket(name=namespace) except ClientError as clientError: raise MinioCallException( f'An error occurred during bucket reading: {clientError}') models = [] for object in bucket.objects.all(): if object.size > 0: model_path = object.key.split('/')[0].rsplit('-', 1) model_name = model_path[0] model_version = model_path[-1] model_size = object.size deployment_count = len( endpoints_using_model(deployments, model_path)) models.append( (model_name, model_version, model_size, deployment_count)) if not models: return f"There are no models present in {namespace} tenant\n" else: return f'Models in {namespace} tenant ' \ f'(model name, model version, model size, deployed count): {models}\n'
def on_post(self, req, resp, tenant_name): namespace = tenant_name body = req.media key = get_key(body) if not tenant_exists(namespace, id_token=req.get_header('Authorization')): raise TenantDoesNotExistException(tenant_name=namespace) abort_upload(bucket=namespace, key=key, multipart_id=body['uploadId']) resp.status = falcon.HTTP_200 resp.body = f"Upload with ID: {body['uploadId']} aborted successfully"
def list_endpoints(namespace: str, id_token: str): if not tenant_exists(namespace, id_token=id_token): raise TenantDoesNotExistException(tenant_name=namespace) apps_api_instance = get_k8s_apps_api_client(id_token) try: deployments = apps_api_instance.list_namespaced_deployment(namespace) except ApiException as apiException: raise KubernetesGetException('endpoint', apiException) endpoints_name_status = get_endpoints_name_status(deployments, namespace) logger.info(endpoints_name_status) return endpoints_name_status
def on_post(self, req, resp, tenant_name): namespace = tenant_name body = req.media key = get_key(body) if not tenant_exists(namespace, id_token=req.get_header('Authorization')): raise TenantDoesNotExistException(tenant_name=namespace) upload_id = create_upload(bucket=namespace, key=key) logger.info("Key: " + key + " ID: " + upload_id) resp.status = falcon.HTTP_200 resp.body = json.dumps({'uploadId': upload_id})
def on_post(self, req, resp, tenant_name): namespace = tenant_name body = req.media key = get_dir_key(body) if not tenant_exists(namespace, id_token=req.get_header('Authorization')): raise TenantDoesNotExistException(tenant_name=namespace) response = create_dir(tenant_name, key) resp.status = falcon.HTTP_200 resp.body = json.dumps({ 'status': 'OK', 'data': { 'dir': response, 'op': 'create_dir' } })
def on_post(self, req, resp, tenant_name): namespace = tenant_name body = req.media key = get_key(body) if not tenant_exists(namespace, id_token=req.params['Authorization']): raise TenantDoesNotExistException(tenant_name=namespace) abort_upload(bucket=namespace, key=key, multipart_id=body['uploadId']) resp.status = falcon.HTTP_200 resp.body = json.dumps({ 'status': 'OK', 'data': { 'uploadId': body['uploadId'], 'op': 'upload_abort' } })
def delete_model(parameters: dict, namespace: str, id_token): # TODO Add checking if model is used by endpoint if not tenant_exists(namespace, id_token): raise TenantDoesNotExistException(namespace) model_path = f"{parameters['modelName']}/{parameters['modelVersion']}/" bucket = minio_resource.Bucket(name=namespace) model_in_bucket = bucket.objects.filter(Prefix=model_path) if not model_exists(model_in_bucket): raise ModelDoesNotExistException(model_path) for key in model_in_bucket: key.delete() logger.info(f'Model {model_path} deleted') return model_path
def list_models(namespace: str, id_token): # TODO Add checking if model is used by endpoint if not tenant_exists(namespace, id_token): raise TenantDoesNotExistException(namespace) try: bucket = minio_resource.Bucket(name=namespace) except ClientError as clientError: raise MinioCallException( f'An error occurred during bucket reading: {clientError}') models = [] for object in bucket.objects.all(): if object.size > 0: model = dict() model_path = object.key.split('/', 2) model['path'] = object.key model['name'] = model_path[0] model['version'] = model_path[1] model['size'] = object.size models.append(model) logger.info(f'Models present in {namespace} tenant: {models}') return models