From 094e91e9c7657af768957ef2407ed7abc21f5872 Mon Sep 17 00:00:00 2001 From: Lu Peng Date: Tue, 22 Apr 2025 00:36:30 -0400 Subject: [PATCH 01/10] Added support to edit single model deployment. --- ads/aqua/extension/deployment_handler.py | 10 + ads/aqua/modeldeployment/deployment.py | 361 ++++++++++++++++-- ads/aqua/modeldeployment/entities.py | 54 ++- .../deployment/aqua_update_deployment.yaml | 36 ++ .../with_extras/aqua/test_deployment.py | 62 +++ 5 files changed, 493 insertions(+), 30 deletions(-) create mode 100644 tests/unitary/with_extras/aqua/test_data/deployment/aqua_update_deployment.yaml diff --git a/ads/aqua/extension/deployment_handler.py b/ads/aqua/extension/deployment_handler.py index 4c4fc2ac5..e8225396f 100644 --- a/ads/aqua/extension/deployment_handler.py +++ b/ads/aqua/extension/deployment_handler.py @@ -88,6 +88,15 @@ def put(self, *args, **kwargs): # noqa: ARG002 return self.finish(AquaDeploymentApp().activate(model_deployment_id)) elif action == "deactivate": return self.finish(AquaDeploymentApp().deactivate(model_deployment_id)) + elif action == "update": + try: + input_data = self.get_json_body() + except Exception as ex: + raise HTTPError(400, Errors.INVALID_INPUT_DATA_FORMAT) from ex + + if not input_data: + raise HTTPError(400, Errors.NO_INPUT_DATA) + return self.finish(AquaDeploymentApp().update(**input_data)) else: raise HTTPError(400, f"The request {self.request.path} is invalid.") @@ -294,5 +303,6 @@ def post(self, *args, **kwargs): # noqa: ARG002 ("deployments/?([^/]*)", AquaDeploymentHandler), ("deployments/?([^/]*)/activate", AquaDeploymentHandler), ("deployments/?([^/]*)/deactivate", AquaDeploymentHandler), + ("deployments/?([^/]*)/update", AquaDeploymentHandler), ("inference", AquaDeploymentInferenceHandler), ] diff --git a/ads/aqua/modeldeployment/deployment.py b/ads/aqua/modeldeployment/deployment.py index 80bb4bd05..508f87e61 100644 --- a/ads/aqua/modeldeployment/deployment.py +++ b/ads/aqua/modeldeployment/deployment.py @@ -17,7 +17,12 @@ ComputeShapeSummary, ContainerPath, ) -from ads.aqua.common.enums import InferenceContainerTypeFamily, ModelFormat, Tags +from ads.aqua.common.enums import ( + InferenceContainerType, + InferenceContainerTypeFamily, + ModelFormat, + Tags, +) from ads.aqua.common.errors import AquaRuntimeError, AquaValueError from ads.aqua.common.utils import ( DEFINED_METADATA_TO_FILE_MAP, @@ -57,6 +62,7 @@ ConfigValidationError, CreateModelDeploymentDetails, ModelDeploymentConfigSummary, + UpdateModelDeploymentDetails, ) from ads.aqua.modeldeployment.utils import MultiModelDeploymentConfigLoader from ads.common.object_storage_details import ObjectStorageDetails @@ -329,6 +335,58 @@ def _create( AquaDeployment An Aqua deployment instance. """ + ( + model_name, + model_type, + container_image_uri, + server_port, + health_check_port, + env_var, + tags, + cmd_var, + ) = self._get_container_details( + aqua_model=aqua_model, + deployment_details=create_deployment_details, + container_config=container_config, + ) + + return self._create_deployment( + create_deployment_details=create_deployment_details, + aqua_model_id=aqua_model.id, + model_name=model_name, + model_type=model_type, + container_image_uri=container_image_uri, + server_port=server_port, + health_check_port=health_check_port, + env_var=env_var, + tags=tags, + cmd_var=cmd_var, + ) + + def _get_container_details( + self, + aqua_model: DataScienceModel, + deployment_details: Union[ + CreateModelDeploymentDetails, UpdateModelDeploymentDetails + ], + container_config: Dict, + ): + """Gets required or optional configurations for building container runtime of model deployment. + + Parameters + ---------- + aqua_model: DataScienceModel + An instance of Aqua data science model. + deployment_details: Union[CreateModelDeploymentDetails, UpdateModelDeploymentDetails] + An instance of either CreateModelDeploymentDetails or UpdateModelDeploymentDetails containing all required and optional + fields for creating or updating a model deployment via Aqua. + container_config: Dict + Container config dictionary. + + Returns + ------- + A tuple of required or optional configurations for container runtime of model deployment. + """ tags = {} for tag in [ Tags.AQUA_SERVICE_MODEL_TAG, @@ -342,7 +400,7 @@ def _create( tags.update({Tags.TASK: aqua_model.freeform_tags.get(Tags.TASK, UNKNOWN)}) # Set up info to get deployment config - config_source_id = create_deployment_details.model_id + config_source_id = deployment_details.model_id model_name = aqua_model.display_name is_fine_tuned_model = Tags.AQUA_FINE_TUNED_MODEL_TAG in aqua_model.freeform_tags @@ -362,8 +420,8 @@ def _create( ) from err # set up env and cmd var - env_var = create_deployment_details.env_var or {} - cmd_var = create_deployment_details.cmd_var or [] + env_var = deployment_details.env_var or {} + cmd_var = deployment_details.cmd_var or [] try: model_path_prefix = aqua_model.custom_metadata_list.get( @@ -397,11 +455,11 @@ def _create( container_type_key = self._get_container_type_key( model=aqua_model, - container_family=create_deployment_details.container_family, + container_family=deployment_details.container_family, ) container_image_uri = ( - create_deployment_details.container_image_uri + deployment_details.container_image_uri or self.get_container_image(container_type=container_type_key) ) if not container_image_uri: @@ -448,7 +506,7 @@ def _create( and container_type_key.lower() == InferenceContainerTypeFamily.AQUA_LLAMA_CPP_CONTAINER_FAMILY ): - model_file = create_deployment_details.model_file + model_file = deployment_details.model_file if model_file is not None: logger.info( f"Overriding {model_file} as model_file for model {aqua_model.id}." @@ -477,18 +535,18 @@ def _create( container_spec = container_config.spec if container_config else UNKNOWN # these params cannot be overridden for Aqua deployments params = container_spec.cli_param if container_spec else UNKNOWN - server_port = create_deployment_details.server_port or ( + server_port = deployment_details.server_port or ( container_spec.server_port if container_spec else None ) # Give precendece to the input parameter - health_check_port = create_deployment_details.health_check_port or ( + health_check_port = deployment_details.health_check_port or ( container_spec.health_check_port if container_spec else None ) deployment_config = self.get_deployment_config(model_id=config_source_id) config_params = deployment_config.configuration.get( - create_deployment_details.instance_shape, ConfigurationItem() + deployment_details.instance_shape, ConfigurationItem() ).parameters.get(get_container_params_type(container_type_key), UNKNOWN) # validate user provided params @@ -530,22 +588,20 @@ def _create( logger.info(f"Env vars used for deploying {aqua_model.id} :{env_var}") - tags = {**tags, **(create_deployment_details.freeform_tags or {})} + tags = {**tags, **(deployment_details.freeform_tags or {})} model_type = ( AQUA_MODEL_TYPE_CUSTOM if is_fine_tuned_model else AQUA_MODEL_TYPE_SERVICE ) - return self._create_deployment( - create_deployment_details=create_deployment_details, - aqua_model_id=aqua_model.id, - model_name=model_name, - model_type=model_type, - container_image_uri=container_image_uri, - server_port=server_port, - health_check_port=health_check_port, - env_var=env_var, - tags=tags, - cmd_var=cmd_var, + return ( + model_name, + model_type, + container_image_uri, + server_port, + health_check_port, + env_var, + tags, + cmd_var, ) def _create_multi( @@ -904,6 +960,239 @@ def list(self, **kwargs) -> List["AquaDeployment"]: return results + @telemetry(entry_point="plugin=deployment&action=update", name="aqua") + def update( + self, + update_deployment_details: Optional[UpdateModelDeploymentDetails] = None, + **kwargs, + ) -> "AquaDeployment": + """ + Updates an Aqua model deployment.\n + For detailed information about CLI flags see: https://github.com/oracle-samples/oci-data-science-ai-samples/blob/main/ai-quick-actions/cli-tips.md#update-model-deployment + + Args: + update_deployment_details : UpdateModelDeploymentDetails, optional + An instance of UpdateModelDeploymentDetails containing all required and optional + fields for updating a model deployment via Aqua. + kwargs: + deployment_id (str): The OCID of model deployment to be update. + instance_shape (Optional[str]): The instance shape used for deployment. + display_name (Optional[str]): The name of the model deployment. + description (Optional[str]): The description of the deployment. + model_id (Optional[str]): The model OCID to deploy. + models (Optional[List[AquaMultiModelRef]]): List of models for multimodel deployment. + instance_count (Optional[int]): Number of instances used for deployment. + log_group_id (Optional[str]): OCI logging group ID for logs. + access_log_id (Optional[str]): OCID for access logs. + predict_log_id (Optional[str]): OCID for prediction logs. + bandwidth_mbps (Optional[int]): Bandwidth limit on the load balancer in Mbps. + web_concurrency (Optional[int]): Number of worker processes/threads for handling requests. + server_port (Optional[int]): Server port for the Docker container image. + health_check_port (Optional[int]): Health check port for the Docker container image. + env_var (Optional[Dict[str, str]]): Environment variables for deployment. + container_family (Optional[str]): Image family of the model deployment container runtime. + memory_in_gbs (Optional[float]): Memory (in GB) for the selected shape. + ocpus (Optional[float]): OCPU count for the selected shape. + model_file (Optional[str]): File used for model deployment. + private_endpoint_id (Optional[str]): Private endpoint ID for model deployment. + container_image_uri (Optional[str]): Image URI for model deployment container runtime. + cmd_var (Optional[List[str]]): Command variables for the container runtime. + freeform_tags (Optional[Dict]): Freeform tags for model deployment. + defined_tags (Optional[Dict]): Defined tags for model deployment. + + Returns + ------- + AquaDeployment + An Aqua deployment instance. + """ + # Build update deployment details from kwargs if not explicitly provided. + if update_deployment_details is None: + try: + update_deployment_details = UpdateModelDeploymentDetails(**kwargs) + except ValidationError as ex: + custom_errors = build_pydantic_error_message(ex) + raise AquaValueError( + f"Invalid parameters for updating model deployment. Error details: {custom_errors}." + ) from ex + + aqua_deployment = ModelDeployment.from_id( + update_deployment_details.deployment_id + ) + aqua_model = DataScienceModel.from_id(aqua_deployment.runtime.model_uri) + + oci_aqua = ( + ( + Tags.AQUA_TAG in aqua_deployment.freeform_tags + or Tags.AQUA_TAG.lower() in aqua_deployment.freeform_tags + ) + if aqua_deployment.freeform_tags + else False + ) + + if not oci_aqua: + raise AquaRuntimeError( + f"Target deployment {aqua_deployment.id} is not Aqua deployment as it does not contain " + f"{Tags.AQUA_TAG} tag." + ) + + model_name = UNKNOWN + is_fine_tuned_model = Tags.AQUA_FINE_TUNED_MODEL_TAG in aqua_model.freeform_tags + model_type = ( + AQUA_MODEL_TYPE_CUSTOM if is_fine_tuned_model else AQUA_MODEL_TYPE_SERVICE + ) + if Tags.MULTIMODEL_TYPE_TAG not in aqua_deployment.freeform_tags: + update_deployment_details.model_id = aqua_model.id + self._update( + model=aqua_model, + model_deployment=aqua_deployment, + update_deployment_details=update_deployment_details, + ) + model_name = aqua_model.display_name + else: + # TODO: update multi-model deployment + pass + + logger.info( + f"Aqua model deployment {aqua_deployment.id} updated for model {aqua_model.id}." + ) + + # we arbitrarily choose last 8 characters of OCID to identify MD in telemetry + telemetry_kwargs = {"ocid": get_ocid_substring(aqua_deployment.id, key_len=8)} + + # tracks unique deployments that were created in the user compartment + self.telemetry.record_event_async( + category=f"aqua/{model_type}/deployment", + action="update", + detail=model_name, + **telemetry_kwargs, + ) + # tracks the shape used for deploying the custom or service models by name + self.telemetry.record_event_async( + category=f"aqua/{model_type}/deployment/update", + action="shape", + detail=update_deployment_details.instance_shape, + value=model_name, + ) + + return AquaDeployment.from_oci_model_deployment( + aqua_deployment.dsc_model_deployment, self.region + ) + + def _update( + self, + model: DataScienceModel, + model_deployment: ModelDeployment, + update_deployment_details: UpdateModelDeploymentDetails, + ): + """Builds the configurations required by single model deployment and updates the deployment. + + Parameters + ---------- + model : DataScienceModel + An instance of Aqua data science model. + model_deployment : ModelDeployment + An instance of Aqua model deployment. + update_deployment_details : UpdateModelDeploymentDetails + An instance of UpdateModelDeploymentDetails containing all required and optional + fields for updating a model deployment via Aqua. + """ + infrastructure = model_deployment.infrastructure + runtime = model_deployment.runtime + # updates model deployment infrastructure + ( + infrastructure.with_shape_name( + update_deployment_details.instance_shape or infrastructure.shape_name + ) + .with_bandwidth_mbps( + update_deployment_details.bandwidth_mbps + or infrastructure.bandwidth_mbps + ) + .with_replica( + update_deployment_details.instance_count or infrastructure.replica + ) + .with_web_concurrency( + update_deployment_details.web_concurrency + or infrastructure.web_concurrency + ) + .with_private_endpoint_id( + update_deployment_details.private_endpoint_id + or infrastructure.private_endpoint_id + ) + ) + if ( + update_deployment_details.log_group_id + and update_deployment_details.access_log_id + ): + ( + infrastructure.with_access_log( + log_group_id=update_deployment_details.log_group_id + or infrastructure.log_group_id, + log_id=update_deployment_details.access_log_id + or infrastructure.access_log.get("log_id", None), + ) + ) + if ( + update_deployment_details.log_group_id + and update_deployment_details.predict_log_id + ): + ( + infrastructure.with_predict_log( + log_group_id=update_deployment_details.log_group_id + or infrastructure.log_group_id, + log_id=update_deployment_details.predict_log_id + or infrastructure.predict_log.get("log_id", None), + ) + ) + if ( + update_deployment_details.memory_in_gbs + and update_deployment_details.ocpus + and infrastructure.shape_name.endswith("Flex") + ): + infrastructure.with_shape_config_details( + ocpus=update_deployment_details.ocpus, + memory_in_gbs=update_deployment_details.memory_in_gbs, + ) + + # updates model deployment runtime + ( + _, + _, + container_image_uri, + server_port, + health_check_port, + env_var, + tags, + cmd_var, + ) = self._get_container_details( + aqua_model=model, + deployment_details=update_deployment_details, + container_config=self.get_container_config(), + ) + ( + runtime.with_image(container_image_uri or runtime.image) + .with_server_port(server_port or runtime.server_port) + .with_health_check_port(health_check_port or runtime.health_check_port) + .with_env(env_var or runtime.env_var) + .with_cmd(cmd_var or runtime.cmd) + ) + + # updates model deployment + ( + model_deployment.with_display_name( + update_deployment_details.display_name or model_deployment.display_name + ) + .with_description( + update_deployment_details.description or model_deployment.description + ) + .with_freeform_tags(**(tags or model_deployment.freeform_tags)) + .with_defined_tags( + **( + update_deployment_details.defined_tags + or model_deployment.defined_tags + ) + ) + ).update(wait_for_completion=False) + @telemetry(entry_point="plugin=deployment&action=delete", name="aqua") def delete(self, model_deployment_id: str): logger.info(f"Deleting model deployment {model_deployment_id}.") @@ -988,6 +1277,29 @@ def get(self, model_deployment_id: str, **kwargs) -> "AquaDeploymentDetail": compartment_id=model_deployment.compartment_id, source_id=model_deployment.id, ) + bandwidth_mbps = model_deployment.model_deployment_configuration_details.model_configuration_details.bandwidth_mbps + environment_configuration_details = model_deployment.model_deployment_configuration_details.environment_configuration_details + inference_mode = environment_configuration_details.environment_variables.get( + "MODEL_DEPLOY_PREDICT_ENDPOINT", None + ) + + image = environment_configuration_details.image + container_family = image[image.rfind("/") + 1 : image.rfind(":")] + container_type = UNKNOWN + if container_family == InferenceContainerTypeFamily.AQUA_VLLM_CONTAINER_FAMILY: + container_type = InferenceContainerType.CONTAINER_TYPE_VLLM.upper() + elif container_family == InferenceContainerTypeFamily.AQUA_TGI_CONTAINER_FAMILY: + container_type = InferenceContainerType.CONTAINER_TYPE_TGI.upper() + elif ( + container_family + == InferenceContainerTypeFamily.AQUA_LLAMA_CPP_CONTAINER_FAMILY + ): + container_type = InferenceContainerType.CONTAINER_TYPE_LLAMA_CPP.upper() + + inference_container = f"{container_type}:{image[image.rfind(':')+1:]}" + + defined_tags = model_deployment.defined_tags + freeform_tags = model_deployment.freeform_tags aqua_deployment = AquaDeployment.from_oci_model_deployment( model_deployment, self.region @@ -1030,6 +1342,11 @@ def get(self, model_deployment_id: str, **kwargs) -> "AquaDeploymentDetail": log_group_id, log_group_name, log_group_url ), log=AquaResourceIdentifier(log_id, log_name, log_url), + bandwidth_mbps=bandwidth_mbps, + inference_mode=inference_mode, + inference_container=inference_container, + defined_tags=defined_tags, + freeform_tags=freeform_tags, ) @telemetry( diff --git a/ads/aqua/modeldeployment/entities.py b/ads/aqua/modeldeployment/entities.py index 5899e5b2f..62d1d3c4a 100644 --- a/ads/aqua/modeldeployment/entities.py +++ b/ads/aqua/modeldeployment/entities.py @@ -208,6 +208,21 @@ class AquaDeploymentDetail(AquaDeployment, DataClassSerializable): log_group: AquaResourceIdentifier = Field(default_factory=AquaResourceIdentifier) log: AquaResourceIdentifier = Field(default_factory=AquaResourceIdentifier) + bandwidth_mbps: Optional[int] = Field( + None, description="Bandwidth limit on the load balancer in Mbps." + ) + inference_container: Optional[str] = Field( + None, description="Inference container of the model deployment." + ) + inference_mode: Optional[str] = Field( + None, description="Inference mode of the model deployment." + ) + defined_tags: Optional[Dict] = Field( + None, description="Defined tags for model deployment." + ) + freeform_tags: Optional[Dict] = Field( + None, description="Freeform tags for model deployment." + ) class Config: extra = "allow" @@ -391,15 +406,9 @@ class Config: extra = "allow" -class CreateModelDeploymentDetails(BaseModel): - """Class for creating Aqua model deployments.""" +class ModelDeploymentBasicDetails(BaseModel): + """Class for Aqua model deployments basic details.""" - instance_shape: str = Field( - ..., description="The instance shape used for deployment." - ) - display_name: str = Field(..., description="The name of the model deployment.") - compartment_id: Optional[str] = Field(None, description="The compartment OCID.") - project_id: Optional[str] = Field(None, description="The project OCID.") description: Optional[str] = Field( None, description="The description of the deployment." ) @@ -470,6 +479,20 @@ class CreateModelDeploymentDetails(BaseModel): None, description="Defined tags for model deployment." ) + class Config: + extra = "ignore" + + +class CreateModelDeploymentDetails(ModelDeploymentBasicDetails): + """Class for creating Aqua model deployments.""" + + instance_shape: str = Field( + ..., description="The instance shape used for deployment." + ) + display_name: str = Field(..., description="The name of the model deployment.") + compartment_id: Optional[str] = Field(None, description="The compartment OCID.") + project_id: Optional[str] = Field(None, description="The project OCID.") + @model_validator(mode="before") @classmethod def validate(cls, values: Any) -> Any: @@ -651,3 +674,18 @@ def validate_multimodel_deployment_feasibility( class Config: extra = "allow" protected_namespaces = () + + +class UpdateModelDeploymentDetails(ModelDeploymentBasicDetails): + """Class for updating Aqua model deployments.""" + + deployment_id: str = Field( + ..., description="The id of model deployment to be updated." + ) + instance_shape: str = Field( + None, description="The instance shape used for deployment." + ) + display_name: str = Field(None, description="The name of the model deployment.") + + class Config: + extra = "ignore" diff --git a/tests/unitary/with_extras/aqua/test_data/deployment/aqua_update_deployment.yaml b/tests/unitary/with_extras/aqua/test_data/deployment/aqua_update_deployment.yaml new file mode 100644 index 000000000..0c3b9e792 --- /dev/null +++ b/tests/unitary/with_extras/aqua/test_data/deployment/aqua_update_deployment.yaml @@ -0,0 +1,36 @@ +kind: deployment +spec: + createdBy: ocid1.user.oc1.. + displayName: model-deployment-name + freeformTags: + OCI_AQUA: active + aqua_model_name: model-name + id: "ocid1.datasciencemodeldeployment.oc1.." + infrastructure: + kind: infrastructure + spec: + bandwidthMbps: 10 + compartmentId: ocid1.compartment.oc1.. + deploymentType: SINGLE_MODEL + policyType: FIXED_SIZE + projectId: ocid1.datascienceproject.oc1.iad. + replica: 1 + shapeName: "VM.GPU.A10.1" + type: datascienceModelDeployment + lifecycleState: ACTIVE + modelDeploymentUrl: "https://modeldeployment.customer-oci.com/ocid1.datasciencemodeldeployment.oc1.." + runtime: + kind: runtime + spec: + env: + BASE_MODEL: service_models/model-name/artifact + MODEL_DEPLOY_ENABLE_STREAMING: 'true' + MODEL_DEPLOY_PREDICT_ENDPOINT: /v1/completions + PARAMS: --served-model-name odsc-llm --seed 42 --trust-remote-code --max-model-len 4096 + healthCheckPort: 8080 + image: "dsmc://image-name:1.0.0.0" + modelUri: "ocid1.datasciencemodeldeployment.oc1.." + serverPort: 8080 + type: container + timeCreated: 2024-01-01T00:00:00.000000+00:00 +type: modelDeployment diff --git a/tests/unitary/with_extras/aqua/test_deployment.py b/tests/unitary/with_extras/aqua/test_deployment.py index b0bc1d5fe..03960313e 100644 --- a/tests/unitary/with_extras/aqua/test_deployment.py +++ b/tests/unitary/with_extras/aqua/test_deployment.py @@ -551,6 +551,14 @@ class TestDataset: "name": "log-name", "url": "https://cloud.oracle.com/logging/search?searchQuery=search \"ocid1.compartment.oc1../ocid1.loggroup.oc1../ocid1.log.oc1..\" | source='ocid1.datasciencemodeldeployment.oc1..' | sort by datetime desc®ions=region-name", }, + "bandwidth_mbps": 10, + "inference_container": ":1.0.0.0", + "inference_mode": "/v1/completions", + "defined_tags": {}, + "freeform_tags": { + "OCI_AQUA": "active", + "aqua_model_name": "model-name", + }, } model_params = { @@ -1831,6 +1839,60 @@ def test_create_deployment_for_multi_model( expected_result["state"] = "CREATING" assert actual_attributes == expected_result + @patch("ads.model.deployment.model_deployment.ModelDeployment.update") + @patch("ads.model.datascience_model.DataScienceModel.from_id") + @patch("ads.model.deployment.model_deployment.ModelDeployment.from_id") + def test_update_single_model_deployment( + self, mock_deployment, mock_model, mock_update + ): + freeform_tags = {"ftag1": "fvalue1", "ftag2": "fvalue2"} + defined_tags = {"dtag1": "dvalue1", "dtag2": "dvalue2"} + model_deployment_obj = ModelDeployment.from_yaml( + uri=os.path.join( + self.curr_dir, "test_data/deployment/aqua_update_deployment.yaml" + ) + ) + model_deployment_dsc_obj = copy.deepcopy(TestDataset.model_deployment_object[0]) + model_deployment_dsc_obj["lifecycle_state"] = "ACTIVE" + model_deployment_dsc_obj["defined_tags"] = defined_tags + model_deployment_dsc_obj["freeform_tags"].update(freeform_tags) + model_deployment_obj.dsc_model_deployment = ( + oci.data_science.models.ModelDeploymentSummary(**model_deployment_dsc_obj) + ) + + mock_deployment.return_value = model_deployment_obj + + mock_model.return_value = DataScienceModel.from_yaml( + uri=os.path.join( + self.curr_dir, "test_data/deployment/aqua_foundation_model.yaml" + ) + ) + + config_json = os.path.join( + self.curr_dir, + "test_data/deployment/deployment_config.json", + ) + + with open(config_json, "r") as _file: + config = json.load(_file) + + self.app.get_deployment_config = MagicMock( + return_value=AquaDeploymentConfig(**config) + ) + + mock_update.return_value = model_deployment_obj + + self.app.update( + **{ + "deployment_id": TestDataset.MODEL_DEPLOYMENT_ID, + "instance_shape": TestDataset.DEPLOYMENT_SHAPE_NAME, + "model_id": TestDataset.MODEL_ID, + "display_name": "updated single model deployment", + } + ) + + mock_update.assert_called_with(wait_for_completion=False) + @parameterized.expand( [ ( From 5ca8b600c50d6ed8ea78abe5445099ca7f1ce741 Mon Sep 17 00:00:00 2001 From: Lu Peng Date: Tue, 22 Apr 2025 00:47:19 -0400 Subject: [PATCH 02/10] Updated pr. --- ads/aqua/modeldeployment/deployment.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ads/aqua/modeldeployment/deployment.py b/ads/aqua/modeldeployment/deployment.py index 29bfc129a..fc177bb19 100644 --- a/ads/aqua/modeldeployment/deployment.py +++ b/ads/aqua/modeldeployment/deployment.py @@ -97,6 +97,8 @@ class AquaDeploymentApp(AquaApp): Creates a model deployment for Aqua Model. get(model_deployment_id: str) -> AquaDeployment: Retrieves details of an Aqua model deployment by its unique identifier. + update(deployment_id: str, instance_shape: str, display_name: str,...) -> AquaDeployment + Updates a model deployment for Aqua Model. list(**kwargs) -> List[AquaModelSummary]: Lists all Aqua deployments within a specified compartment and/or project. get_deployment_config(self, model_id: str) -> AquaDeploymentConfig: @@ -184,9 +186,7 @@ def create( # validate instance shape availability in compartment available_shapes = [ shape.name.lower() - for shape in self.list_shapes( - compartment_id=compartment_id - ) + for shape in self.list_shapes(compartment_id=compartment_id) ] if create_deployment_details.instance_shape.lower() not in available_shapes: @@ -1171,7 +1171,7 @@ def _update( runtime.with_image(container_image_uri or runtime.image) .with_server_port(server_port or runtime.server_port) .with_health_check_port(health_check_port or runtime.health_check_port) - .with_env(env_var or runtime.env_var) + .with_env(env_var or runtime.env) .with_cmd(cmd_var or runtime.cmd) ) From 5f824db6b035f5ba93525e9cd4d34290eac6c399 Mon Sep 17 00:00:00 2001 From: Lu Peng Date: Tue, 22 Apr 2025 10:50:27 -0400 Subject: [PATCH 03/10] Updated pr. --- tests/unitary/with_extras/aqua/test_deployment.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/unitary/with_extras/aqua/test_deployment.py b/tests/unitary/with_extras/aqua/test_deployment.py index 03960313e..4e718e6db 100644 --- a/tests/unitary/with_extras/aqua/test_deployment.py +++ b/tests/unitary/with_extras/aqua/test_deployment.py @@ -1840,11 +1840,17 @@ def test_create_deployment_for_multi_model( assert actual_attributes == expected_result @patch("ads.model.deployment.model_deployment.ModelDeployment.update") + @patch.object(AquaApp, "get_container_config") @patch("ads.model.datascience_model.DataScienceModel.from_id") @patch("ads.model.deployment.model_deployment.ModelDeployment.from_id") def test_update_single_model_deployment( - self, mock_deployment, mock_model, mock_update + self, mock_deployment, mock_model, mock_get_container_config, mock_update ): + mock_get_container_config.return_value = ( + AquaContainerConfig.from_service_config( + service_containers=TestDataset.CONTAINER_LIST + ) + ) freeform_tags = {"ftag1": "fvalue1", "ftag2": "fvalue2"} defined_tags = {"dtag1": "dvalue1", "dtag2": "dvalue2"} model_deployment_obj = ModelDeployment.from_yaml( From bf7a281b6619a169363902da4844aaa111f708a3 Mon Sep 17 00:00:00 2001 From: Lu Peng Date: Tue, 22 Apr 2025 11:41:35 -0400 Subject: [PATCH 04/10] Updated pr. --- .../with_extras/aqua/test_deployment.py | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/tests/unitary/with_extras/aqua/test_deployment.py b/tests/unitary/with_extras/aqua/test_deployment.py index 4e718e6db..56095ca41 100644 --- a/tests/unitary/with_extras/aqua/test_deployment.py +++ b/tests/unitary/with_extras/aqua/test_deployment.py @@ -1840,17 +1840,12 @@ def test_create_deployment_for_multi_model( assert actual_attributes == expected_result @patch("ads.model.deployment.model_deployment.ModelDeployment.update") - @patch.object(AquaApp, "get_container_config") + @patch("ads.aqua.modeldeployment.AquaDeploymentApp._get_container_details") @patch("ads.model.datascience_model.DataScienceModel.from_id") @patch("ads.model.deployment.model_deployment.ModelDeployment.from_id") def test_update_single_model_deployment( - self, mock_deployment, mock_model, mock_get_container_config, mock_update + self, mock_deployment, mock_model, mock_get_container_details, mock_update ): - mock_get_container_config.return_value = ( - AquaContainerConfig.from_service_config( - service_containers=TestDataset.CONTAINER_LIST - ) - ) freeform_tags = {"ftag1": "fvalue1", "ftag2": "fvalue2"} defined_tags = {"dtag1": "dvalue1", "dtag2": "dvalue2"} model_deployment_obj = ModelDeployment.from_yaml( @@ -1874,16 +1869,20 @@ def test_update_single_model_deployment( ) ) - config_json = os.path.join( - self.curr_dir, - "test_data/deployment/deployment_config.json", - ) - - with open(config_json, "r") as _file: - config = json.load(_file) - - self.app.get_deployment_config = MagicMock( - return_value=AquaDeploymentConfig(**config) + mock_get_container_details.return_value = ( + None, + None, + "dsmc://image-name:1.0.0.0", + "8080", + "8080", + { + "BASE_MODEL": "service_models/model-name/artifact", + "MODEL_DEPLOY_ENABLE_STREAMING": "true", + "MODEL_DEPLOY_PREDICT_ENDPOINT": "/v1/completions", + "PARAMS": "--served-model-name odsc-llm --seed 42", + }, + {**freeform_tags, **defined_tags}, + [], ) mock_update.return_value = model_deployment_obj @@ -1891,8 +1890,6 @@ def test_update_single_model_deployment( self.app.update( **{ "deployment_id": TestDataset.MODEL_DEPLOYMENT_ID, - "instance_shape": TestDataset.DEPLOYMENT_SHAPE_NAME, - "model_id": TestDataset.MODEL_ID, "display_name": "updated single model deployment", } ) From 253a9b50a76f5e31185a95cc167404fc216eb2f7 Mon Sep 17 00:00:00 2001 From: Lu Peng Date: Tue, 22 Apr 2025 12:15:34 -0400 Subject: [PATCH 05/10] Updated pr. --- tests/unitary/with_extras/aqua/test_deployment.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/unitary/with_extras/aqua/test_deployment.py b/tests/unitary/with_extras/aqua/test_deployment.py index 56095ca41..6d2bdf974 100644 --- a/tests/unitary/with_extras/aqua/test_deployment.py +++ b/tests/unitary/with_extras/aqua/test_deployment.py @@ -1841,11 +1841,22 @@ def test_create_deployment_for_multi_model( @patch("ads.model.deployment.model_deployment.ModelDeployment.update") @patch("ads.aqua.modeldeployment.AquaDeploymentApp._get_container_details") + @patch.object(AquaApp, "get_container_config") @patch("ads.model.datascience_model.DataScienceModel.from_id") @patch("ads.model.deployment.model_deployment.ModelDeployment.from_id") def test_update_single_model_deployment( - self, mock_deployment, mock_model, mock_get_container_details, mock_update + self, + mock_deployment, + mock_model, + mock_get_container_config, + mock_get_container_details, + mock_update, ): + mock_get_container_config.return_value = ( + AquaContainerConfig.from_service_config( + service_containers=TestDataset.CONTAINER_LIST + ) + ) freeform_tags = {"ftag1": "fvalue1", "ftag2": "fvalue2"} defined_tags = {"dtag1": "dvalue1", "dtag2": "dvalue2"} model_deployment_obj = ModelDeployment.from_yaml( From 400f6199ec24a480d68cd79adb4c15824ba4b977 Mon Sep 17 00:00:00 2001 From: Lu Peng Date: Tue, 22 Apr 2025 13:07:51 -0400 Subject: [PATCH 06/10] Updated pr. --- ads/aqua/modeldeployment/deployment.py | 30 +++++++++++++++++++------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/ads/aqua/modeldeployment/deployment.py b/ads/aqua/modeldeployment/deployment.py index fc177bb19..56b10639e 100644 --- a/ads/aqua/modeldeployment/deployment.py +++ b/ads/aqua/modeldeployment/deployment.py @@ -1040,7 +1040,6 @@ def update( AQUA_MODEL_TYPE_CUSTOM if is_fine_tuned_model else AQUA_MODEL_TYPE_SERVICE ) if Tags.MULTIMODEL_TYPE_TAG not in aqua_deployment.freeform_tags: - update_deployment_details.model_id = aqua_model.id self._update( model=aqua_model, model_deployment=aqua_deployment, @@ -1153,6 +1152,7 @@ def _update( ) # updates model deployment runtime + update_deployment_details.model_id = model.id ( _, _, @@ -1168,13 +1168,23 @@ def _update( container_config=self.get_container_config(), ) ( - runtime.with_image(container_image_uri or runtime.image) - .with_server_port(server_port or runtime.server_port) - .with_health_check_port(health_check_port or runtime.health_check_port) - .with_env(env_var or runtime.env) - .with_cmd(cmd_var or runtime.cmd) + runtime.with_image( + update_deployment_details.container_image_uri or runtime.image + ) + .with_server_port( + update_deployment_details.server_port or runtime.server_port + ) + .with_health_check_port( + update_deployment_details.health_check_port or runtime.health_check_port + ) ) + if update_deployment_details.env_var: + runtime.with_env(env_var) + + if update_deployment_details.cmd_var: + runtime.with_cmd(cmd_var) + # updates model deployment ( model_deployment.with_display_name( @@ -1183,14 +1193,18 @@ def _update( .with_description( update_deployment_details.description or model_deployment.description ) - .with_freeform_tags(**(tags or model_deployment.freeform_tags)) .with_defined_tags( **( update_deployment_details.defined_tags or model_deployment.defined_tags ) ) - ).update(wait_for_completion=False) + ) + + if update_deployment_details.freeform_tags: + model_deployment.with_freeform_tags(**tags) + + model_deployment.update(wait_for_completion=False) @telemetry(entry_point="plugin=deployment&action=delete", name="aqua") def delete(self, model_deployment_id: str): From 7b02d3f1694b64b555a4d71583beed094d9c7c29 Mon Sep 17 00:00:00 2001 From: Lu Peng Date: Tue, 22 Apr 2025 13:44:59 -0400 Subject: [PATCH 07/10] Updated pr. --- ads/aqua/modeldeployment/deployment.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ads/aqua/modeldeployment/deployment.py b/ads/aqua/modeldeployment/deployment.py index 56b10639e..33948f038 100644 --- a/ads/aqua/modeldeployment/deployment.py +++ b/ads/aqua/modeldeployment/deployment.py @@ -81,6 +81,7 @@ ModelDeploymentInfrastructure, ModelDeploymentMode, ) +from ads.model.deployment.common.utils import State from ads.model.model_metadata import ModelCustomMetadataItem from ads.telemetry import telemetry @@ -1017,6 +1018,13 @@ def update( aqua_deployment = ModelDeployment.from_id( update_deployment_details.deployment_id ) + + if aqua_deployment.lifecycle_state != State.ACTIVE.name: + raise AquaValueError( + f"Invalid parameter `deployment_id`. Model deployment has to be {State.ACTIVE.name} to be updated." + f"Wait for the status to become {State.ACTIVE.name} or specify a different `deployment_id`." + ) + aqua_model = DataScienceModel.from_id(aqua_deployment.runtime.model_uri) oci_aqua = ( From bc57a236954e22b834964223c936d648d11d7697 Mon Sep 17 00:00:00 2001 From: Lu Peng Date: Thu, 24 Apr 2025 13:35:34 -0400 Subject: [PATCH 08/10] Updated pr. --- ads/aqua/modeldeployment/deployment.py | 36 ++++++++++++-------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/ads/aqua/modeldeployment/deployment.py b/ads/aqua/modeldeployment/deployment.py index 33948f038..afad1825b 100644 --- a/ads/aqua/modeldeployment/deployment.py +++ b/ads/aqua/modeldeployment/deployment.py @@ -1015,6 +1015,14 @@ def update( f"Invalid parameters for updating model deployment. Error details: {custom_errors}." ) from ex + if ( + update_deployment_details.container_family + or update_deployment_details.container_image_uri + ): + raise AquaValueError( + "Updating inference container is not supported at this moment for Aqau Deployment." + ) + aqua_deployment = ModelDeployment.from_id( update_deployment_details.deployment_id ) @@ -1131,10 +1139,8 @@ def _update( ): ( infrastructure.with_access_log( - log_group_id=update_deployment_details.log_group_id - or infrastructure.log_group_id, - log_id=update_deployment_details.access_log_id - or infrastructure.access_log.get("log_id", None), + log_group_id=update_deployment_details.log_group_id, + log_id=update_deployment_details.access_log_id, ) ) if ( @@ -1143,10 +1149,8 @@ def _update( ): ( infrastructure.with_predict_log( - log_group_id=update_deployment_details.log_group_id - or infrastructure.log_group_id, - log_id=update_deployment_details.predict_log_id - or infrastructure.predict_log.get("log_id", None), + log_group_id=update_deployment_details.log_group_id, + log_id=update_deployment_details.predict_log_id, ) ) if ( @@ -1175,19 +1179,11 @@ def _update( deployment_details=update_deployment_details, container_config=self.get_container_config(), ) - ( - runtime.with_image( - update_deployment_details.container_image_uri or runtime.image - ) - .with_server_port( - update_deployment_details.server_port or runtime.server_port - ) - .with_health_check_port( - update_deployment_details.health_check_port or runtime.health_check_port - ) - ) - if update_deployment_details.env_var: + if ( + update_deployment_details.env_var + or update_deployment_details.instance_shape + ): runtime.with_env(env_var) if update_deployment_details.cmd_var: From 8dcb2540a26920cdf75e3f0f1572c87ba569ce28 Mon Sep 17 00:00:00 2001 From: Lu Peng Date: Thu, 24 Apr 2025 22:25:55 -0400 Subject: [PATCH 09/10] Updated pr. --- ads/aqua/modeldeployment/deployment.py | 58 +++++++++---------- ads/aqua/modeldeployment/entities.py | 8 +-- .../with_extras/aqua/test_deployment.py | 16 ++--- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/ads/aqua/modeldeployment/deployment.py b/ads/aqua/modeldeployment/deployment.py index afad1825b..3a191850c 100644 --- a/ads/aqua/modeldeployment/deployment.py +++ b/ads/aqua/modeldeployment/deployment.py @@ -60,9 +60,9 @@ AquaDeploymentDetail, ConfigurationItem, ConfigValidationError, - CreateModelDeploymentDetails, ModelDeploymentConfigSummary, - UpdateModelDeploymentDetails, + ModelDeploymentCreateSpec, + ModelDeploymentUpdateSpec, ) from ads.aqua.modeldeployment.utils import MultiModelDeploymentConfigLoader from ads.common.object_storage_details import ObjectStorageDetails @@ -120,7 +120,7 @@ class AquaDeploymentApp(AquaApp): @telemetry(entry_point="plugin=deployment&action=create", name="aqua") def create( self, - create_deployment_details: Optional[CreateModelDeploymentDetails] = None, + create_deployment_details: Optional[ModelDeploymentCreateSpec] = None, **kwargs, ) -> "AquaDeployment": """ @@ -128,8 +128,8 @@ def create( For detailed information about CLI flags see: https://github.com/oracle-samples/oci-data-science-ai-samples/blob/main/ai-quick-actions/cli-tips.md#create-model-deployment Args: - create_deployment_details : CreateModelDeploymentDetails, optional - An instance of CreateModelDeploymentDetails containing all required and optional + create_deployment_details : ModelDeploymentCreateSpec, optional + An instance of ModelDeploymentCreateSpec containing all required and optional fields for creating a model deployment via Aqua. kwargs: instance_shape (str): The instance shape used for deployment. @@ -166,7 +166,7 @@ def create( # Build deployment details from kwargs if not explicitly provided. if create_deployment_details is None: try: - create_deployment_details = CreateModelDeploymentDetails(**kwargs) + create_deployment_details = ModelDeploymentCreateSpec(**kwargs) except ValidationError as ex: custom_errors = build_pydantic_error_message(ex) raise AquaValueError( @@ -316,7 +316,7 @@ def create( def _create( self, aqua_model: DataScienceModel, - create_deployment_details: CreateModelDeploymentDetails, + create_deployment_details: ModelDeploymentCreateSpec, container_config: Dict, ) -> AquaDeployment: """Builds the configurations required by single model deployment and creates the deployment. @@ -325,8 +325,8 @@ def _create( ---------- aqua_model : DataScienceModel An instance of Aqua data science model. - create_deployment_details : CreateModelDeploymentDetails - An instance of CreateModelDeploymentDetails containing all required and optional + create_deployment_details : ModelDeploymentCreateSpec + An instance of ModelDeploymentCreateSpec containing all required and optional fields for creating a model deployment via Aqua. container_config: Dict Container config dictionary. @@ -345,7 +345,7 @@ def _create( env_var, tags, cmd_var, - ) = self._get_container_details( + ) = self._get_runtime_config_from_model_deployment( aqua_model=aqua_model, deployment_details=create_deployment_details, container_config=container_config, @@ -364,12 +364,10 @@ def _create( cmd_var=cmd_var, ) - def _get_container_details( + def _get_runtime_config_from_model_deployment( self, aqua_model: DataScienceModel, - deployment_details: Union[ - CreateModelDeploymentDetails, UpdateModelDeploymentDetails - ], + deployment_details: Union[ModelDeploymentCreateSpec, ModelDeploymentUpdateSpec], container_config: Dict, ): """Gets required or optional configurations for building container runtime of model deployment. @@ -378,8 +376,8 @@ def _get_container_details( ---------- aqua_model: DataScienceModel An instance of Aqua data science model. - deployment_details: Union[CreateModelDeploymentDetails, UpdateModelDeploymentDetails] - An instance of either CreateModelDeploymentDetails or UpdateModelDeploymentDetails containing all required and optional + deployment_details: Union[ModelDeploymentCreateSpec, ModelDeploymentUpdateSpec] + An instance of either ModelDeploymentCreateSpec or ModelDeploymentUpdateSpec containing all required and optional fields for creating or updating a model deployment via Aqua. container_config: Dict Container config dictionary. @@ -608,7 +606,7 @@ def _create_multi( self, aqua_model: DataScienceModel, model_config_summary: ModelDeploymentConfigSummary, - create_deployment_details: CreateModelDeploymentDetails, + create_deployment_details: ModelDeploymentCreateSpec, container_config: AquaContainerConfig, ) -> AquaDeployment: """Builds the environment variables required by multi deployment container and creates the deployment. @@ -619,8 +617,8 @@ def _create_multi( Summary Model Deployment configuration for the group of models. aqua_model : DataScienceModel An instance of Aqua data science model. - create_deployment_details : CreateModelDeploymentDetails - An instance of CreateModelDeploymentDetails containing all required and optional + create_deployment_details : ModelDeploymentCreateSpec + An instance of ModelDeploymentCreateSpec containing all required and optional fields for creating a model deployment via Aqua. container_config: Dict Container config dictionary. @@ -752,7 +750,7 @@ def _create_multi( def _create_deployment( self, - create_deployment_details: CreateModelDeploymentDetails, + create_deployment_details: ModelDeploymentCreateSpec, aqua_model_id: str, model_name: str, model_type: str, @@ -767,8 +765,8 @@ def _create_deployment( Parameters ---------- - create_deployment_details : CreateModelDeploymentDetails - An instance of CreateModelDeploymentDetails containing all required and optional + create_deployment_details : ModelDeploymentCreateSpec + An instance of ModelDeploymentCreateSpec containing all required and optional fields for creating a model deployment via Aqua. aqua_model_id: str The id of the aqua model to be deployed. @@ -963,7 +961,7 @@ def list(self, **kwargs) -> List["AquaDeployment"]: @telemetry(entry_point="plugin=deployment&action=update", name="aqua") def update( self, - update_deployment_details: Optional[UpdateModelDeploymentDetails] = None, + update_deployment_details: Optional[ModelDeploymentUpdateSpec] = None, **kwargs, ) -> "AquaDeployment": """ @@ -971,8 +969,8 @@ def update( For detailed information about CLI flags see: https://github.com/oracle-samples/oci-data-science-ai-samples/blob/main/ai-quick-actions/cli-tips.md#update-model-deployment Args: - update_deployment_details : UpdateModelDeploymentDetails, optional - An instance of UpdateModelDeploymentDetails containing all required and optional + update_deployment_details : ModelDeploymentUpdateSpec, optional + An instance of ModelDeploymentUpdateSpec containing all required and optional fields for updating a model deployment via Aqua. kwargs: deployment_id (str): The OCID of model deployment to be update. @@ -1008,7 +1006,7 @@ def update( # Build update deployment details from kwargs if not explicitly provided. if update_deployment_details is None: try: - update_deployment_details = UpdateModelDeploymentDetails(**kwargs) + update_deployment_details = ModelDeploymentUpdateSpec(**kwargs) except ValidationError as ex: custom_errors = build_pydantic_error_message(ex) raise AquaValueError( @@ -1096,7 +1094,7 @@ def _update( self, model: DataScienceModel, model_deployment: ModelDeployment, - update_deployment_details: UpdateModelDeploymentDetails, + update_deployment_details: ModelDeploymentUpdateSpec, ): """Builds the configurations required by single model deployment and updates the deployment. @@ -1106,8 +1104,8 @@ def _update( An instance of Aqua data science model. model_deployment : ModelDeployment An instance of Aqua model deployment. - update_deployment_details : UpdateModelDeploymentDetails - An instance of UpdateModelDeploymentDetails containing all required and optional + update_deployment_details : ModelDeploymentUpdateSpec + An instance of ModelDeploymentUpdateSpec containing all required and optional fields for updating a model deployment via Aqua. """ infrastructure = model_deployment.infrastructure @@ -1174,7 +1172,7 @@ def _update( env_var, tags, cmd_var, - ) = self._get_container_details( + ) = self._get_runtime_config_from_model_deployment( aqua_model=model, deployment_details=update_deployment_details, container_config=self.get_container_config(), diff --git a/ads/aqua/modeldeployment/entities.py b/ads/aqua/modeldeployment/entities.py index 62d1d3c4a..8182cb8ae 100644 --- a/ads/aqua/modeldeployment/entities.py +++ b/ads/aqua/modeldeployment/entities.py @@ -406,7 +406,7 @@ class Config: extra = "allow" -class ModelDeploymentBasicDetails(BaseModel): +class ModelDeploymentSpec(BaseModel): """Class for Aqua model deployments basic details.""" description: Optional[str] = Field( @@ -483,7 +483,7 @@ class Config: extra = "ignore" -class CreateModelDeploymentDetails(ModelDeploymentBasicDetails): +class ModelDeploymentCreateSpec(ModelDeploymentSpec): """Class for creating Aqua model deployments.""" instance_shape: str = Field( @@ -676,7 +676,7 @@ class Config: protected_namespaces = () -class UpdateModelDeploymentDetails(ModelDeploymentBasicDetails): +class ModelDeploymentUpdateSpec(ModelDeploymentSpec): """Class for updating Aqua model deployments.""" deployment_id: str = Field( @@ -688,4 +688,4 @@ class UpdateModelDeploymentDetails(ModelDeploymentBasicDetails): display_name: str = Field(None, description="The name of the model deployment.") class Config: - extra = "ignore" + extra = "allow" diff --git a/tests/unitary/with_extras/aqua/test_deployment.py b/tests/unitary/with_extras/aqua/test_deployment.py index 6d2bdf974..7f5738714 100644 --- a/tests/unitary/with_extras/aqua/test_deployment.py +++ b/tests/unitary/with_extras/aqua/test_deployment.py @@ -41,7 +41,7 @@ AquaDeploymentConfig, AquaDeploymentDetail, ConfigValidationError, - CreateModelDeploymentDetails, + ModelDeploymentCreateSpec, ModelDeploymentConfigSummary, ModelParams, ) @@ -1719,7 +1719,7 @@ def test_create_deployment_for_tei_byoc_embedding_model( @patch("ads.model.deployment.model_deployment.ModelDeployment.deploy") @patch("ads.aqua.modeldeployment.AquaDeploymentApp.get_deployment_config") @patch( - "ads.aqua.modeldeployment.entities.CreateModelDeploymentDetails.validate_multimodel_deployment_feasibility" + "ads.aqua.modeldeployment.entities.ModelDeploymentCreateSpec.validate_multimodel_deployment_feasibility" ) def test_create_deployment_for_multi_model( self, @@ -1840,7 +1840,9 @@ def test_create_deployment_for_multi_model( assert actual_attributes == expected_result @patch("ads.model.deployment.model_deployment.ModelDeployment.update") - @patch("ads.aqua.modeldeployment.AquaDeploymentApp._get_container_details") + @patch( + "ads.aqua.modeldeployment.AquaDeploymentApp._get_runtime_config_from_model_deployment" + ) @patch.object(AquaApp, "get_container_config") @patch("ads.model.datascience_model.DataScienceModel.from_id") @patch("ads.model.deployment.model_deployment.ModelDeployment.from_id") @@ -1849,7 +1851,7 @@ def test_update_single_model_deployment( mock_deployment, mock_model, mock_get_container_config, - mock_get_container_details, + mock_get_runtime_config_from_model_deployment, mock_update, ): mock_get_container_config.return_value = ( @@ -1880,7 +1882,7 @@ def test_update_single_model_deployment( ) ) - mock_get_container_details.return_value = ( + mock_get_runtime_config_from_model_deployment.return_value = ( None, None, "dsmc://image-name:1.0.0.0", @@ -2117,7 +2119,7 @@ def validate_multimodel_deployment_feasibility_helper( for x in models ] - mock_create_deployment_details = CreateModelDeploymentDetails( + mock_create_deployment_details = ModelDeploymentCreateSpec( models=aqua_models, instance_shape=instance_shape, display_name=display_name, @@ -2125,7 +2127,7 @@ def validate_multimodel_deployment_feasibility_helper( ) else: model_id = "model_a" - mock_create_deployment_details = CreateModelDeploymentDetails( + mock_create_deployment_details = ModelDeploymentCreateSpec( model_id=model_id, instance_shape=instance_shape, display_name=display_name, From fe815745357939f27212a12043a3125141b6f785 Mon Sep 17 00:00:00 2001 From: Lu Peng Date: Thu, 24 Apr 2025 22:27:08 -0400 Subject: [PATCH 10/10] Updated pr. --- ads/aqua/modeldeployment/entities.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ads/aqua/modeldeployment/entities.py b/ads/aqua/modeldeployment/entities.py index 8182cb8ae..bf3e54b03 100644 --- a/ads/aqua/modeldeployment/entities.py +++ b/ads/aqua/modeldeployment/entities.py @@ -480,7 +480,7 @@ class ModelDeploymentSpec(BaseModel): ) class Config: - extra = "ignore" + extra = "allow" class ModelDeploymentCreateSpec(ModelDeploymentSpec):