From 70eefeb1c667717d265d74b9f53c852d07bc39bc Mon Sep 17 00:00:00 2001 From: Isabella Basso do Amaral Date: Mon, 5 Feb 2024 12:14:57 -0300 Subject: [PATCH] add DocArtifact type Closes: #263 Signed-off-by: Isabella Basso do Amaral --- api/openapi/model-registry.yaml | 15 +- internal/constants/constants.go | 1 + .../generated/mlmd_openapi_converter.gen.go | 36 ++ .../generated/openapi_converter.gen.go | 5 + .../generated/openapi_mlmd_converter.gen.go | 64 +++ .../converter/mlmd_converter_util_test.go | 65 +++ internal/converter/mlmd_openapi_converter.go | 6 + .../converter/mlmd_openapi_converter_util.go | 15 +- internal/converter/openapi_converter.go | 6 + internal/converter/openapi_converter_test.go | 3 + internal/converter/openapi_converter_util.go | 8 + internal/converter/openapi_mlmd_converter.go | 8 + .../converter/openapi_mlmd_converter_util.go | 35 ++ internal/mapper/mapper.go | 90 ++-- internal/mapper/mapper_test.go | 46 +- internal/mlmdtypes/mlmdtypes.go | 17 + .../api_model_registry_service_service.go | 15 +- pkg/api/api.go | 8 + pkg/core/core.go | 219 ++++++--- pkg/core/core_test.go | 339 ++++++++++--- pkg/openapi/.openapi-generator/FILES | 1 + pkg/openapi/api_model_registry_service.go | 4 +- pkg/openapi/model_artifact.go | 40 ++ pkg/openapi/model_doc_artifact.go | 453 ++++++++++++++++++ 24 files changed, 1320 insertions(+), 179 deletions(-) create mode 100644 pkg/openapi/model_doc_artifact.go diff --git a/api/openapi/model-registry.yaml b/api/openapi/model-registry.yaml index d9c7ec08..c702eee7 100644 --- a/api/openapi/model-registry.yaml +++ b/api/openapi/model-registry.yaml @@ -367,8 +367,7 @@ paths: "500": $ref: "#/components/responses/InternalServerError" operationId: getModelVersionArtifacts - summary: List All ModelVersion's artifacts - description: Gets a list of all `Artifact` entities for the `ModelVersion`. + summary: List all artifacts associated with the `ModelVersion` post: requestBody: description: A new or existing `Artifact` to be associated with the `ModelVersion`. @@ -979,6 +978,16 @@ components: artifactType: type: string default: "model-artifact" + DocArtifact: + description: A document. + type: object + allOf: + - $ref: "#/components/schemas/BaseArtifact" + - type: object + properties: + artifactType: + type: string + default: "doc-artifact" RegisteredModel: description: A registered model in model registry. A registered model has ModelVersion children. allOf: @@ -1272,10 +1281,12 @@ components: Artifact: oneOf: - $ref: "#/components/schemas/ModelArtifact" + - $ref: "#/components/schemas/DocArtifact" discriminator: propertyName: artifactType mapping: model-artifact: "#/components/schemas/ModelArtifact" + doc-artifact: "#/components/schemas/DocArtifact" description: A metadata Artifact Entity. BaseArtifact: allOf: diff --git a/internal/constants/constants.go b/internal/constants/constants.go index d218d3fb..eabfa968 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -5,6 +5,7 @@ const ( RegisteredModelTypeName = "odh.RegisteredModel" ModelVersionTypeName = "odh.ModelVersion" ModelArtifactTypeName = "odh.ModelArtifact" + DocArtifactTypeName = "odh.DocArtifact" ServingEnvironmentTypeName = "odh.ServingEnvironment" InferenceServiceTypeName = "odh.InferenceService" ServeModelTypeName = "odh.ServeModel" diff --git a/internal/converter/generated/mlmd_openapi_converter.gen.go b/internal/converter/generated/mlmd_openapi_converter.gen.go index 6ec760ee..92ab100f 100755 --- a/internal/converter/generated/mlmd_openapi_converter.gen.go +++ b/internal/converter/generated/mlmd_openapi_converter.gen.go @@ -11,6 +11,42 @@ import ( type MLMDToOpenAPIConverterImpl struct{} +func (c *MLMDToOpenAPIConverterImpl) ConvertDocArtifact(source *proto.Artifact) (*openapi.DocArtifact, error) { + var pOpenapiDocArtifact *openapi.DocArtifact + if source != nil { + var openapiDocArtifact openapi.DocArtifact + mapStringOpenapiMetadataValue, err := converter.MapMLMDCustomProperties((*source).CustomProperties) + if err != nil { + return nil, err + } + openapiDocArtifact.CustomProperties = &mapStringOpenapiMetadataValue + openapiDocArtifact.Description = converter.MapDescription((*source).Properties) + var pString *string + if (*source).ExternalId != nil { + xstring := *(*source).ExternalId + pString = &xstring + } + openapiDocArtifact.ExternalID = pString + var pString2 *string + if (*source).Uri != nil { + xstring2 := *(*source).Uri + pString2 = &xstring2 + } + openapiDocArtifact.Uri = pString2 + openapiDocArtifact.State = converter.MapMLMDArtifactState((*source).State) + openapiDocArtifact.Name = converter.MapNameFromOwned((*source).Name) + openapiDocArtifact.Id = converter.Int64ToString((*source).Id) + openapiDocArtifact.CreateTimeSinceEpoch = converter.Int64ToString((*source).CreateTimeSinceEpoch) + openapiDocArtifact.LastUpdateTimeSinceEpoch = converter.Int64ToString((*source).LastUpdateTimeSinceEpoch) + xstring3, err := converter.MapArtifactType(source) + if err != nil { + return nil, fmt.Errorf("error setting field ArtifactType: %w", err) + } + openapiDocArtifact.ArtifactType = xstring3 + pOpenapiDocArtifact = &openapiDocArtifact + } + return pOpenapiDocArtifact, nil +} func (c *MLMDToOpenAPIConverterImpl) ConvertInferenceService(source *proto.Context) (*openapi.InferenceService, error) { var pOpenapiInferenceService *openapi.InferenceService if source != nil { diff --git a/internal/converter/generated/openapi_converter.gen.go b/internal/converter/generated/openapi_converter.gen.go index 2603742b..96cccad6 100755 --- a/internal/converter/generated/openapi_converter.gen.go +++ b/internal/converter/generated/openapi_converter.gen.go @@ -564,6 +564,11 @@ func (c *OpenAPIConverterImpl) ConvertServingEnvironmentUpdate(source *openapi.S } return pOpenapiServingEnvironment, nil } +func (c *OpenAPIConverterImpl) OverrideNotEditableForDocArtifact(source converter.OpenapiUpdateWrapper[openapi.DocArtifact]) (openapi.DocArtifact, error) { + openapiDocArtifact := converter.InitDocArtifactWithUpdate(source) + _ = source + return openapiDocArtifact, nil +} func (c *OpenAPIConverterImpl) OverrideNotEditableForInferenceService(source converter.OpenapiUpdateWrapper[openapi.InferenceService]) (openapi.InferenceService, error) { openapiInferenceService := converter.InitInferenceServiceWithUpdate(source) var pString *string diff --git a/internal/converter/generated/openapi_mlmd_converter.gen.go b/internal/converter/generated/openapi_mlmd_converter.gen.go index 13116a54..5badda5f 100755 --- a/internal/converter/generated/openapi_mlmd_converter.gen.go +++ b/internal/converter/generated/openapi_mlmd_converter.gen.go @@ -11,6 +11,70 @@ import ( type OpenAPIToMLMDConverterImpl struct{} +func (c *OpenAPIToMLMDConverterImpl) ConvertDocArtifact(source *converter.OpenAPIModelWrapper[openapi.DocArtifact]) (*proto.Artifact, error) { + var pProtoArtifact *proto.Artifact + if source != nil { + var protoArtifact proto.Artifact + var pString *string + if (*source).Model != nil { + pString = (*source).Model.Id + } + pInt64, err := converter.StringToInt64(pString) + if err != nil { + return nil, fmt.Errorf("error setting field Id: %w", err) + } + protoArtifact.Id = pInt64 + protoArtifact.Name = converter.MapDocArtifactName(source) + pInt642 := (*source).TypeId + protoArtifact.TypeId = &pInt642 + protoArtifact.Type = converter.MapDocArtifactType((*source).Model) + var pString2 *string + if (*source).Model != nil { + pString2 = (*source).Model.Uri + } + var pString3 *string + if pString2 != nil { + xstring := *pString2 + pString3 = &xstring + } + protoArtifact.Uri = pString3 + var pString4 *string + if (*source).Model != nil { + pString4 = (*source).Model.ExternalID + } + var pString5 *string + if pString4 != nil { + xstring2 := *pString4 + pString5 = &xstring2 + } + protoArtifact.ExternalId = pString5 + mapStringPProtoValue, err := converter.MapDocArtifactProperties((*source).Model) + if err != nil { + return nil, fmt.Errorf("error setting field Properties: %w", err) + } + protoArtifact.Properties = mapStringPProtoValue + var pMapStringOpenapiMetadataValue *map[string]openapi.MetadataValue + if (*source).Model != nil { + pMapStringOpenapiMetadataValue = (*source).Model.CustomProperties + } + mapStringPProtoValue2, err := converter.MapOpenAPICustomProperties(pMapStringOpenapiMetadataValue) + if err != nil { + return nil, fmt.Errorf("error setting field CustomProperties: %w", err) + } + protoArtifact.CustomProperties = mapStringPProtoValue2 + var pOpenapiArtifactState *openapi.ArtifactState + if (*source).Model != nil { + pOpenapiArtifactState = (*source).Model.State + } + pProtoArtifact_State, err := converter.MapOpenAPIArtifactState(pOpenapiArtifactState) + if err != nil { + return nil, fmt.Errorf("error setting field State: %w", err) + } + protoArtifact.State = pProtoArtifact_State + pProtoArtifact = &protoArtifact + } + return pProtoArtifact, nil +} func (c *OpenAPIToMLMDConverterImpl) ConvertInferenceService(source *converter.OpenAPIModelWrapper[openapi.InferenceService]) (*proto.Context, error) { var pProtoContext *proto.Context if source != nil { diff --git a/internal/converter/mlmd_converter_util_test.go b/internal/converter/mlmd_converter_util_test.go index 9b52bfa1..27ac3d81 100644 --- a/internal/converter/mlmd_converter_util_test.go +++ b/internal/converter/mlmd_converter_util_test.go @@ -323,6 +323,65 @@ func TestMapModelArtifactName(t *testing.T) { assertion.Regexp(".*:v1", *name) } +func TestMapDocArtifactProperties(t *testing.T) { + assertion := setup(t) + + props, err := MapDocArtifactProperties(&openapi.DocArtifact{ + Name: of("v1"), + Description: of("my model art description"), + }) + assertion.Nil(err) + assertion.Equal(1, len(props)) + assertion.Equal("my model art description", props["description"].GetStringValue()) + + props, err = MapModelArtifactProperties(&openapi.ModelArtifact{ + Name: of("v1"), + }) + assertion.Nil(err) + assertion.Equal(0, len(props)) +} + +func TestMapDocArtifactType(t *testing.T) { + assertion := setup(t) + + typeName := MapModelArtifactType(&openapi.ModelArtifact{}) + assertion.NotNil(typeName) + assertion.Equal(constants.ModelArtifactTypeName, *typeName) +} + +func TestMapDocArtifactName(t *testing.T) { + assertion := setup(t) + + name := MapDocArtifactName(&OpenAPIModelWrapper[openapi.DocArtifact]{ + TypeId: 123, + ParentResourceId: of("parent"), + Model: &openapi.DocArtifact{ + Name: of("v1"), + }, + }) + assertion.NotNil(name) + assertion.Equal("parent:v1", *name) + + name = MapDocArtifactName(&OpenAPIModelWrapper[openapi.DocArtifact]{ + TypeId: 123, + ParentResourceId: of("parent"), + Model: &openapi.DocArtifact{ + Name: nil, + }, + }) + assertion.NotNil(name) + assertion.Regexp("parent:.*", *name) + + name = MapDocArtifactName(&OpenAPIModelWrapper[openapi.DocArtifact]{ + TypeId: 123, + Model: &openapi.DocArtifact{ + Name: of("v1"), + }, + }) + assertion.NotNil(name) + assertion.Regexp(".*:v1", *name) +} + func TestMapOpenAPIArtifactState(t *testing.T) { assertion := setup(t) @@ -523,6 +582,12 @@ func TestMapArtifactType(t *testing.T) { assertion.Nil(err) assertion.Equal("model-artifact", artifactType) + artifactType, err = MapArtifactType(&proto.Artifact{ + Type: of(constants.DocArtifactTypeName), + }) + assertion.Nil(err) + assertion.Equal("doc-artifact", artifactType) + artifactType, err = MapArtifactType(&proto.Artifact{ Type: of("Invalid"), }) diff --git a/internal/converter/mlmd_openapi_converter.go b/internal/converter/mlmd_openapi_converter.go index 8bfa3e53..993ba585 100644 --- a/internal/converter/mlmd_openapi_converter.go +++ b/internal/converter/mlmd_openapi_converter.go @@ -35,6 +35,12 @@ type MLMDToOpenAPIConverter interface { // goverter:map Properties ServiceAccountName | MapModelArtifactServiceAccountName ConvertModelArtifact(source *proto.Artifact) (*openapi.ModelArtifact, error) + // goverter:map Name | MapNameFromOwned + // goverter:map . ArtifactType | MapArtifactType + // goverter:map State | MapMLMDArtifactState + // goverter:map Properties Description | MapDescription + ConvertDocArtifact(source *proto.Artifact) (*openapi.DocArtifact, error) + // goverter:map Name | MapNameFromOwned // goverter:map Properties Description | MapDescription ConvertServingEnvironment(source *proto.Context) (*openapi.ServingEnvironment, error) diff --git a/internal/converter/mlmd_openapi_converter_util.go b/internal/converter/mlmd_openapi_converter_util.go index 67f444dc..b6bb863a 100644 --- a/internal/converter/mlmd_openapi_converter_util.go +++ b/internal/converter/mlmd_openapi_converter_util.go @@ -80,15 +80,24 @@ func MapPropertyAuthor(properties map[string]*proto.Value) *string { return MapStringProperty(properties, "author") } -// MODEL ARTIFACT +// ARTIFACT func MapArtifactType(source *proto.Artifact) (string, error) { - if source.Type != nil && *source.Type == constants.ModelArtifactTypeName { + if source.Type == nil { + return "", fmt.Errorf("artifact type is nil") + } + switch *source.Type { + case constants.ModelArtifactTypeName: return "model-artifact", nil + case constants.DocArtifactTypeName: + return "doc-artifact", nil + default: + return "", fmt.Errorf("invalid artifact type found: %v", source.Type) } - return "", fmt.Errorf("invalid artifact type found: %v", source.Type) } +// MODEL ARTIFACT + func MapRegisteredModelState(properties map[string]*proto.Value) *openapi.RegisteredModelState { state, ok := properties["state"] if !ok { diff --git a/internal/converter/openapi_converter.go b/internal/converter/openapi_converter.go index 5d504c6c..eb7486be 100644 --- a/internal/converter/openapi_converter.go +++ b/internal/converter/openapi_converter.go @@ -61,6 +61,12 @@ type OpenAPIConverter interface { // goverter:ignore Id CreateTimeSinceEpoch LastUpdateTimeSinceEpoch Description ExternalID CustomProperties State Author OverrideNotEditableForModelVersion(source OpenapiUpdateWrapper[openapi.ModelVersion]) (openapi.ModelVersion, error) + // Ignore all fields that ARE editable + // goverter:default InitDocArtifactWithUpdate + // goverter:autoMap Existing + // goverter:ignore Id Name ArtifactType CreateTimeSinceEpoch LastUpdateTimeSinceEpoch Description ExternalID CustomProperties Uri State + OverrideNotEditableForDocArtifact(source OpenapiUpdateWrapper[openapi.DocArtifact]) (openapi.DocArtifact, error) + // Ignore all fields that ARE editable // goverter:default InitModelArtifactWithUpdate // goverter:autoMap Existing diff --git a/internal/converter/openapi_converter_test.go b/internal/converter/openapi_converter_test.go index a2f1d431..8b571f41 100644 --- a/internal/converter/openapi_converter_test.go +++ b/internal/converter/openapi_converter_test.go @@ -30,6 +30,9 @@ func newVisitor(t *testing.T, f *ast.File) visitor { "ModelVersion": { obj: openapi.ModelVersion{}, }, + "DocArtifact": { + obj: openapi.DocArtifact{}, + }, "ModelArtifact": { obj: openapi.ModelArtifact{}, }, diff --git a/internal/converter/openapi_converter_util.go b/internal/converter/openapi_converter_util.go index c1bd6c8c..3a492fd7 100644 --- a/internal/converter/openapi_converter_util.go +++ b/internal/converter/openapi_converter_util.go @@ -6,6 +6,7 @@ type OpenAPIModel interface { openapi.RegisteredModel | openapi.ModelVersion | openapi.ModelArtifact | + openapi.DocArtifact | openapi.ServingEnvironment | openapi.InferenceService | openapi.ServeModel @@ -41,6 +42,13 @@ func InitModelVersionWithUpdate(source OpenapiUpdateWrapper[openapi.ModelVersion return openapi.ModelVersion{} } +func InitDocArtifactWithUpdate(source OpenapiUpdateWrapper[openapi.DocArtifact]) openapi.DocArtifact { + if source.Update != nil { + return *source.Update + } + return openapi.DocArtifact{} +} + func InitModelArtifactWithUpdate(source OpenapiUpdateWrapper[openapi.ModelArtifact]) openapi.ModelArtifact { if source.Update != nil { return *source.Update diff --git a/internal/converter/openapi_mlmd_converter.go b/internal/converter/openapi_mlmd_converter.go index 0652d06d..521e2c6c 100644 --- a/internal/converter/openapi_mlmd_converter.go +++ b/internal/converter/openapi_mlmd_converter.go @@ -44,6 +44,14 @@ type OpenAPIToMLMDConverter interface { // goverter:ignore state sizeCache unknownFields SystemMetadata CreateTimeSinceEpoch LastUpdateTimeSinceEpoch ConvertModelArtifact(source *OpenAPIModelWrapper[openapi.ModelArtifact]) (*proto.Artifact, error) + // goverter:autoMap Model + // goverter:map . Name | MapDocArtifactName + // goverter:map Model Type | MapDocArtifactType + // goverter:map Model Properties | MapDocArtifactProperties + // goverter:map Model.State State | MapOpenAPIArtifactState + // goverter:ignore state sizeCache unknownFields SystemMetadata CreateTimeSinceEpoch LastUpdateTimeSinceEpoch + ConvertDocArtifact(source *OpenAPIModelWrapper[openapi.DocArtifact]) (*proto.Artifact, error) + // goverter:autoMap Model // goverter:map Model Type | MapServingEnvironmentType // goverter:map Model Properties | MapServingEnvironmentProperties diff --git a/internal/converter/openapi_mlmd_converter_util.go b/internal/converter/openapi_mlmd_converter_util.go index f42ff1d0..de521424 100644 --- a/internal/converter/openapi_mlmd_converter_util.go +++ b/internal/converter/openapi_mlmd_converter_util.go @@ -218,6 +218,41 @@ func MapOpenAPIArtifactState(source *openapi.ArtifactState) (*proto.Artifact_Sta return (*proto.Artifact_State)(&val), nil } +// DOC ARTIFACT + +// get DocArtifact MLMD type name +func MapDocArtifactType(_ *openapi.DocArtifact) *string { + return of(constants.DocArtifactTypeName) +} + +func MapDocArtifactProperties(source *openapi.DocArtifact) (map[string]*proto.Value, error) { + props := make(map[string]*proto.Value) + if source == nil { + return nil, nil + } + if source.Description != nil { + props["description"] = &proto.Value{ + Value: &proto.Value_StringValue{ + StringValue: *source.Description, + }, + } + } + return props, nil +} + +// maps the user-provided name into MLMD one, i.e., prefixing it with either the parent resource id or a generated +// uuid. If not provided, autogenerate the name itself +func MapDocArtifactName(source *OpenAPIModelWrapper[openapi.DocArtifact]) *string { + // openapi.Artifact is defined with optional name, so build arbitrary name for this artifact if missing + var artifactName string + if (*source).Model.Name != nil { + artifactName = *(*source).Model.Name + } else { + artifactName = uuid.New().String() + } + return of(PrefixWhenOwned(source.ParentResourceId, artifactName)) +} + // MODEL ARTIFACT // MapModelArtifactProperties maps ModelArtifact fields to specific MLMD properties diff --git a/internal/mapper/mapper.go b/internal/mapper/mapper.go index 6ac31b5f..271ea743 100644 --- a/internal/mapper/mapper.go +++ b/internal/mapper/mapper.go @@ -27,43 +27,49 @@ func NewMapper(mlmdTypes map[string]int64) *Mapper { // Utilities for OpenAPI --> MLMD mapping, make use of generated Converters func (m *Mapper) MapFromRegisteredModel(registeredModel *openapi.RegisteredModel) (*proto.Context, error) { - ctx, err := m.OpenAPIConverter.ConvertRegisteredModel(&converter.OpenAPIModelWrapper[openapi.RegisteredModel]{ + return m.OpenAPIConverter.ConvertRegisteredModel(&converter.OpenAPIModelWrapper[openapi.RegisteredModel]{ TypeId: m.MLMDTypes[constants.RegisteredModelTypeName], Model: registeredModel, }) - if err != nil { - return nil, err - } - - return ctx, nil } func (m *Mapper) MapFromModelVersion(modelVersion *openapi.ModelVersion, registeredModelId string, registeredModelName *string) (*proto.Context, error) { - ctx, err := m.OpenAPIConverter.ConvertModelVersion(&converter.OpenAPIModelWrapper[openapi.ModelVersion]{ + return m.OpenAPIConverter.ConvertModelVersion(&converter.OpenAPIModelWrapper[openapi.ModelVersion]{ TypeId: m.MLMDTypes[constants.ModelVersionTypeName], Model: modelVersion, ParentResourceId: ®isteredModelId, ModelName: registeredModelName, }) - if err != nil { - return nil, err - } - - return ctx, nil } func (m *Mapper) MapFromModelArtifact(modelArtifact *openapi.ModelArtifact, modelVersionId *string) (*proto.Artifact, error) { - - artifact, err := m.OpenAPIConverter.ConvertModelArtifact(&converter.OpenAPIModelWrapper[openapi.ModelArtifact]{ + return m.OpenAPIConverter.ConvertModelArtifact(&converter.OpenAPIModelWrapper[openapi.ModelArtifact]{ TypeId: m.MLMDTypes[constants.ModelArtifactTypeName], Model: modelArtifact, ParentResourceId: modelVersionId, }) - if err != nil { - return nil, err - } +} - return artifact, nil +func (m *Mapper) MapFromDocArtifact(docArtifact *openapi.DocArtifact, modelVersionId *string) (*proto.Artifact, error) { + return m.OpenAPIConverter.ConvertDocArtifact(&converter.OpenAPIModelWrapper[openapi.DocArtifact]{ + TypeId: m.MLMDTypes[constants.DocArtifactTypeName], + Model: docArtifact, + ParentResourceId: modelVersionId, + }) +} + +func (m *Mapper) MapFromArtifact(artifact *openapi.Artifact, modelVersionId *string) (*proto.Artifact, error) { + if artifact == nil { + return nil, fmt.Errorf("invalid artifact pointer, can't map from nil") + } + if artifact.ModelArtifact != nil { + return m.MapFromModelArtifact(artifact.ModelArtifact, modelVersionId) + } + if artifact.DocArtifact != nil { + return m.MapFromDocArtifact(artifact.DocArtifact, modelVersionId) + } + // TODO: print type on error + return nil, fmt.Errorf("unknown artifact type") } func (m *Mapper) MapFromModelArtifacts(modelArtifacts []openapi.ModelArtifact, modelVersionId *string) ([]*proto.Artifact, error) { @@ -82,41 +88,26 @@ func (m *Mapper) MapFromModelArtifacts(modelArtifacts []openapi.ModelArtifact, m } func (m *Mapper) MapFromServingEnvironment(servingEnvironment *openapi.ServingEnvironment) (*proto.Context, error) { - ctx, err := m.OpenAPIConverter.ConvertServingEnvironment(&converter.OpenAPIModelWrapper[openapi.ServingEnvironment]{ + return m.OpenAPIConverter.ConvertServingEnvironment(&converter.OpenAPIModelWrapper[openapi.ServingEnvironment]{ TypeId: m.MLMDTypes[constants.ServingEnvironmentTypeName], Model: servingEnvironment, }) - if err != nil { - return nil, err - } - - return ctx, nil } func (m *Mapper) MapFromInferenceService(inferenceService *openapi.InferenceService, servingEnvironmentId string) (*proto.Context, error) { - ctx, err := m.OpenAPIConverter.ConvertInferenceService(&converter.OpenAPIModelWrapper[openapi.InferenceService]{ + return m.OpenAPIConverter.ConvertInferenceService(&converter.OpenAPIModelWrapper[openapi.InferenceService]{ TypeId: m.MLMDTypes[constants.InferenceServiceTypeName], Model: inferenceService, ParentResourceId: &servingEnvironmentId, }) - if err != nil { - return nil, err - } - - return ctx, nil } func (m *Mapper) MapFromServeModel(serveModel *openapi.ServeModel, inferenceServiceId string) (*proto.Execution, error) { - ctx, err := m.OpenAPIConverter.ConvertServeModel(&converter.OpenAPIModelWrapper[openapi.ServeModel]{ + return m.OpenAPIConverter.ConvertServeModel(&converter.OpenAPIModelWrapper[openapi.ServeModel]{ TypeId: m.MLMDTypes[constants.ServeModelTypeName], Model: serveModel, ParentResourceId: &inferenceServiceId, }) - if err != nil { - return nil, err - } - - return ctx, nil } // Utilities for MLMD --> OpenAPI mapping, make use of generated Converters @@ -133,6 +124,33 @@ func (m *Mapper) MapToModelArtifact(art *proto.Artifact) (*openapi.ModelArtifact return mapTo(art, m.MLMDTypes, constants.ModelArtifactTypeName, m.MLMDConverter.ConvertModelArtifact) } +func (m *Mapper) MapToDocArtifact(art *proto.Artifact) (*openapi.DocArtifact, error) { + return mapTo(art, m.MLMDTypes, constants.DocArtifactTypeName, m.MLMDConverter.ConvertDocArtifact) +} + +func (m *Mapper) MapToArtifact(art *proto.Artifact) (*openapi.Artifact, error) { + if art == nil { + return nil, fmt.Errorf("invalid artifact pointer, can't map from nil") + } + if art.GetType() == "" { + return nil, fmt.Errorf("invalid artifact type, can't map from nil") + } + switch art.GetType() { + case constants.ModelArtifactTypeName: + ma, err := m.MapToModelArtifact(art) + return &openapi.Artifact{ + ModelArtifact: ma, + }, err + case constants.DocArtifactTypeName: + da, err := m.MapToDocArtifact(art) + return &openapi.Artifact{ + DocArtifact: da, + }, err + default: + return nil, fmt.Errorf("unknown artifact type: %s", art.GetType()) + } +} + func (m *Mapper) MapToServingEnvironment(ctx *proto.Context) (*openapi.ServingEnvironment, error) { return mapTo(ctx, m.MLMDTypes, constants.ServingEnvironmentTypeName, m.MLMDConverter.ConvertServingEnvironment) } diff --git a/internal/mapper/mapper_test.go b/internal/mapper/mapper_test.go index 4996e14c..7ad7b98a 100644 --- a/internal/mapper/mapper_test.go +++ b/internal/mapper/mapper_test.go @@ -14,15 +14,17 @@ const ( invalidTypeId = int64(9999) registeredModelTypeId = int64(1) modelVersionTypeId = int64(2) - modelArtifactTypeId = int64(3) - servingEnvironmentTypeId = int64(4) - inferenceServiceTypeId = int64(5) - serveModelTypeId = int64(6) + docArtifactTypeId = int64(3) + modelArtifactTypeId = int64(4) + servingEnvironmentTypeId = int64(5) + inferenceServiceTypeId = int64(6) + serveModelTypeId = int64(7) ) var typesMap = map[string]int64{ constants.RegisteredModelTypeName: registeredModelTypeId, constants.ModelVersionTypeName: modelVersionTypeId, + constants.DocArtifactTypeName: docArtifactTypeId, constants.ModelArtifactTypeName: modelArtifactTypeId, constants.ServingEnvironmentTypeName: servingEnvironmentTypeId, constants.InferenceServiceTypeName: inferenceServiceTypeId, @@ -53,10 +55,23 @@ func TestMapFromModelVersion(t *testing.T) { assertion.Equal(modelVersionTypeId, ctx.GetTypeId()) } +func TestMapFromDocArtifact(t *testing.T) { + assertion, m := setup(t) + + ctx, err := m.MapFromArtifact(&openapi.Artifact{ + DocArtifact: &openapi.DocArtifact{Name: of("DocArtifact")}, + }, of("2")) + assertion.Nil(err) + assertion.Equal("2:DocArtifact", ctx.GetName()) + assertion.Equal(docArtifactTypeId, ctx.GetTypeId()) +} + func TestMapFromModelArtifact(t *testing.T) { assertion, m := setup(t) - ctx, err := m.MapFromModelArtifact(&openapi.ModelArtifact{Name: of("ModelArtifact")}, of("2")) + ctx, err := m.MapFromArtifact(&openapi.Artifact{ + ModelArtifact: &openapi.ModelArtifact{Name: of("ModelArtifact")}, + }, of("2")) assertion.Nil(err) assertion.Equal("2:ModelArtifact", ctx.GetName()) assertion.Equal(modelArtifactTypeId, ctx.GetTypeId()) @@ -167,9 +182,18 @@ func TestMapToModelVersionInvalid(t *testing.T) { assertion.Equal(fmt.Sprintf("invalid entity: expected %s but received odh.OtherEntity, please check the provided id", constants.ModelVersionTypeName), err.Error()) } +func TestMapToDocArtifact(t *testing.T) { + assertion, m := setup(t) + _, err := m.MapToArtifact(&proto.Artifact{ + TypeId: of(docArtifactTypeId), + Type: of(constants.DocArtifactTypeName), + }) + assertion.Nil(err) +} + func TestMapToModelArtifact(t *testing.T) { assertion, m := setup(t) - _, err := m.MapToModelArtifact(&proto.Artifact{ + _, err := m.MapToArtifact(&proto.Artifact{ TypeId: of(modelArtifactTypeId), Type: of(constants.ModelArtifactTypeName), }) @@ -178,21 +202,21 @@ func TestMapToModelArtifact(t *testing.T) { func TestMapToModelArtifactMissingType(t *testing.T) { assertion, m := setup(t) - _, err := m.MapToModelArtifact(&proto.Artifact{ + _, err := m.MapToArtifact(&proto.Artifact{ TypeId: of(modelArtifactTypeId), }) assertion.NotNil(err) - assertion.Equal("error setting field ArtifactType: invalid artifact type found: ", err.Error()) + assertion.Equal("invalid artifact type, can't map from nil", err.Error()) } -func TestMapToModelArtifactInvalid(t *testing.T) { +func TestMapToArtifactInvalid(t *testing.T) { assertion, m := setup(t) - _, err := m.MapToModelArtifact(&proto.Artifact{ + _, err := m.MapToArtifact(&proto.Artifact{ TypeId: of(invalidTypeId), Type: of("odh.OtherEntity"), }) assertion.NotNil(err) - assertion.Equal(fmt.Sprintf("invalid entity: expected %s but received odh.OtherEntity, please check the provided id", constants.ModelArtifactTypeName), err.Error()) + assertion.Equal("unknown artifact type: odh.OtherEntity", err.Error()) } func TestMapToServingEnvironment(t *testing.T) { diff --git a/internal/mlmdtypes/mlmdtypes.go b/internal/mlmdtypes/mlmdtypes.go index f8ab687d..7d6b4220 100644 --- a/internal/mlmdtypes/mlmdtypes.go +++ b/internal/mlmdtypes/mlmdtypes.go @@ -14,6 +14,7 @@ var ( registeredModelTypeName = apiutils.Of(constants.RegisteredModelTypeName) modelVersionTypeName = apiutils.Of(constants.ModelVersionTypeName) modelArtifactTypeName = apiutils.Of(constants.ModelArtifactTypeName) + docArtifactTypeName = apiutils.Of(constants.DocArtifactTypeName) servingEnvironmentTypeName = apiutils.Of(constants.ServingEnvironmentTypeName) inferenceServiceTypeName = apiutils.Of(constants.InferenceServiceTypeName) serveModelTypeName = apiutils.Of(constants.ServeModelTypeName) @@ -50,6 +51,16 @@ func CreateMLMDTypes(cc grpc.ClientConnInterface) (map[string]int64, error) { }, } + docArtifactReq := proto.PutArtifactTypeRequest{ + CanAddFields: canAddFields, + ArtifactType: &proto.ArtifactType{ + Name: docArtifactTypeName, + Properties: map[string]proto.PropertyType{ + "description": proto.PropertyType_STRING, + }, + }, + } + modelArtifactReq := proto.PutArtifactTypeRequest{ CanAddFields: canAddFields, ArtifactType: &proto.ArtifactType{ @@ -112,6 +123,11 @@ func CreateMLMDTypes(cc grpc.ClientConnInterface) (map[string]int64, error) { return nil, fmt.Errorf("error setting up context type %s: %v", *modelVersionTypeName, err) } + docArtifactResp, err := client.PutArtifactType(context.Background(), &docArtifactReq) + if err != nil { + return nil, fmt.Errorf("error setting up artifact type %s: %v", *docArtifactTypeName, err) + } + modelArtifactResp, err := client.PutArtifactType(context.Background(), &modelArtifactReq) if err != nil { return nil, fmt.Errorf("error setting up artifact type %s: %v", *modelArtifactTypeName, err) @@ -135,6 +151,7 @@ func CreateMLMDTypes(cc grpc.ClientConnInterface) (map[string]int64, error) { typesMap := map[string]int64{ constants.RegisteredModelTypeName: registeredModelResp.GetTypeId(), constants.ModelVersionTypeName: modelVersionResp.GetTypeId(), + constants.DocArtifactTypeName: docArtifactResp.GetTypeId(), constants.ModelArtifactTypeName: modelArtifactResp.GetTypeId(), constants.ServingEnvironmentTypeName: servingEnvironmentResp.GetTypeId(), constants.InferenceServiceTypeName: inferenceServiceResp.GetTypeId(), diff --git a/internal/server/openapi/api_model_registry_service_service.go b/internal/server/openapi/api_model_registry_service_service.go index 4d617174..e1134a4c 100644 --- a/internal/server/openapi/api_model_registry_service_service.go +++ b/internal/server/openapi/api_model_registry_service_service.go @@ -11,8 +11,6 @@ package openapi import ( "context" - "errors" - "net/http" "github.com/opendatahub-io/model-registry/internal/apiutils" "github.com/opendatahub-io/model-registry/internal/converter" @@ -111,17 +109,12 @@ func (s *ModelRegistryServiceAPIService) CreateModelVersion(ctx context.Context, // CreateModelVersionArtifact - Create an Artifact in a ModelVersion func (s *ModelRegistryServiceAPIService) CreateModelVersionArtifact(ctx context.Context, modelversionId string, artifact model.Artifact) (ImplResponse, error) { - if artifact.ModelArtifact == nil { - return Response(http.StatusNotImplemented, nil), errors.New("unsupported artifactType") - } - result, err := s.coreApi.UpsertModelArtifact(artifact.ModelArtifact, &modelversionId) + result, err := s.coreApi.UpsertArtifact(&artifact, &modelversionId) if err != nil { return Response(500, model.Error{Message: err.Error()}), nil } - artifactResult := model.Artifact{ - ModelArtifact: result, - } - return Response(201, artifactResult), nil + return Response(201, result), nil + // return Response(http.StatusNotImplemented, nil), errors.New("unsupported artifactType") // TODO return Response(200, Artifact{}), nil // TODO return Response(401, Error{}), nil // TODO return Response(404, Error{}), nil @@ -354,7 +347,7 @@ func (s *ModelRegistryServiceAPIService) GetModelVersionArtifacts(ctx context.Co if err != nil { return Response(500, model.Error{Message: err.Error()}), nil } - result, err := s.coreApi.GetModelArtifacts(listOpts, &modelversionId) + result, err := s.coreApi.GetArtifacts(listOpts, &modelversionId) if err != nil { return Response(500, model.Error{Message: err.Error()}), nil } diff --git a/pkg/api/api.go b/pkg/api/api.go index dd2dd4bc..33f16540 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -50,6 +50,14 @@ type ModelRegistryApi interface { // if registeredModelId is provided, return all ModelVersion instances belonging to a specific RegisteredModel GetModelVersions(listOptions ListOptions, registeredModelId *string) (*openapi.ModelVersionList, error) + // ARTIFACT + + UpsertArtifact(artifact *openapi.Artifact, modelVersionId *string) (*openapi.Artifact, error) + + GetArtifactById(id string) (*openapi.Artifact, error) + + GetArtifacts(listOptions ListOptions, modelVersionId *string) (*openapi.ArtifactList, error) + // MODEL ARTIFACT // UpsertModelArtifact create a new Artifact or update an Artifact associated to a specific diff --git a/pkg/core/core.go b/pkg/core/core.go index e04a5dd5..d812130e 100644 --- a/pkg/core/core.go +++ b/pkg/core/core.go @@ -21,6 +21,7 @@ var ( registeredModelTypeName = apiutils.Of(constants.RegisteredModelTypeName) modelVersionTypeName = apiutils.Of(constants.ModelVersionTypeName) modelArtifactTypeName = apiutils.Of(constants.ModelArtifactTypeName) + docArtifactTypeName = apiutils.Of(constants.DocArtifactTypeName) servingEnvironmentTypeName = apiutils.Of(constants.ServingEnvironmentTypeName) inferenceServiceTypeName = apiutils.Of(constants.InferenceServiceTypeName) serveModelTypeName = apiutils.Of(constants.ServeModelTypeName) @@ -72,6 +73,12 @@ func BuildTypesMap(cc grpc.ClientConnInterface) (map[string]int64, error) { if err != nil { return nil, fmt.Errorf("error getting context type %s: %v", *modelVersionTypeName, err) } + docArtifactResp, err := client.GetArtifactType(context.Background(), &proto.GetArtifactTypeRequest{ + TypeName: docArtifactTypeName, + }) + if err != nil { + return nil, fmt.Errorf("error getting artifact type %s: %v", *docArtifactTypeName, err) + } modelArtifactArtifactTypeReq := proto.GetArtifactTypeRequest{ TypeName: modelArtifactTypeName, } @@ -104,6 +111,7 @@ func BuildTypesMap(cc grpc.ClientConnInterface) (map[string]int64, error) { typesMap := map[string]int64{ constants.RegisteredModelTypeName: registeredModelResp.ContextType.GetId(), constants.ModelVersionTypeName: modelVersionResp.ContextType.GetId(), + constants.DocArtifactTypeName: docArtifactResp.ArtifactType.GetId(), constants.ModelArtifactTypeName: modelArtifactResp.ArtifactType.GetId(), constants.ServingEnvironmentTypeName: servingEnvironmentResp.ContextType.GetId(), constants.InferenceServiceTypeName: inferenceServiceResp.ContextType.GetId(), @@ -366,7 +374,8 @@ func (serv *ModelRegistryService) UpsertModelVersion(modelVersion *openapi.Model _, err = serv.mlmdClient.PutParentContexts(context.Background(), &proto.PutParentContextsRequest{ ParentContexts: []*proto.ParentContext{{ ChildId: modelId, - ParentId: registeredModelId}}, + ParentId: registeredModelId, + }}, TransactionOptions: &proto.TransactionOptions{}, }) if err != nil { @@ -452,11 +461,11 @@ func (serv *ModelRegistryService) getModelVersionByArtifactId(id string) (*opena } if len(getParentResp.Contexts) > 1 { - return nil, fmt.Errorf("multiple model versions found for model artifact %s", id) + return nil, fmt.Errorf("multiple model versions found for artifact %s", id) } if len(getParentResp.Contexts) == 0 { - return nil, fmt.Errorf("no model version found for model artifact %s", id) + return nil, fmt.Errorf("no model version found for artifact %s", id) } modelVersion, err := serv.mapper.MapToModelVersion(getParentResp.Contexts[0]) @@ -542,60 +551,94 @@ func (serv *ModelRegistryService) GetModelVersions(listOptions api.ListOptions, return &toReturn, nil } -// MODEL ARTIFACTS - -// UpsertModelArtifact creates a new model artifact if the provided model artifact's ID is nil, -// or updates an existing model artifact if the ID is provided. -// If a model version ID is provided and the model artifact is newly created, establishes an -// explicit attribution between the model version and the created model artifact. -func (serv *ModelRegistryService) UpsertModelArtifact(modelArtifact *openapi.ModelArtifact, modelVersionId *string) (*openapi.ModelArtifact, error) { - var err error - var existing *openapi.ModelArtifact - - if modelArtifact.Id == nil { - // create - glog.Info("Creating new model artifact") - if modelVersionId == nil { - return nil, fmt.Errorf("missing model version id, cannot create model artifact without model version") +// ARTIFACTS + +// UpsertArtifact creates a new artifact if the provided artifact's ID is nil, or updates an existing artifact if the +// ID is provided. +// A model version ID must be provided to disambiguate between artifacts. +// Upon creation, new artifacts will be associated with their corresponding model version. +func (serv *ModelRegistryService) UpsertArtifact(artifact *openapi.Artifact, modelVersionId *string) (*openapi.Artifact, error) { + if artifact == nil { + return nil, fmt.Errorf("invalid artifact pointer, can't upsert nil") + } + creating := false + if ma := artifact.ModelArtifact; ma != nil { + if ma.Id == nil { + creating = true + glog.Info("Creating model artifact") + if modelVersionId == nil { + return nil, fmt.Errorf("missing model version id, cannot create artifact without model version") + } + _, err := serv.GetModelVersionById(*modelVersionId) + if err != nil { + return nil, fmt.Errorf("no model version found for id %s", *modelVersionId) + } + } else { + glog.Info("Updating model artifact") + existing, err := serv.GetModelArtifactById(*ma.Id) + if err != nil { + return nil, err + } + + withNotEditable, err := serv.openapiConv.OverrideNotEditableForModelArtifact(converter.NewOpenapiUpdateWrapper(existing, ma)) + if err != nil { + return nil, err + } + ma = &withNotEditable + + _, err = serv.getModelVersionByArtifactId(*ma.Id) + if err != nil { + return nil, err + } } - _, err = serv.GetModelVersionById(*modelVersionId) - if err != nil { - return nil, err + } else if da := artifact.DocArtifact; da != nil { + if da.Id == nil { + creating = true + glog.Info("Creating doc artifact") + if modelVersionId == nil { + return nil, fmt.Errorf("missing model version id, cannot create artifact without model version") + } + _, err := serv.GetModelVersionById(*modelVersionId) + if err != nil { + return nil, fmt.Errorf("no model version found for id %s", *modelVersionId) + } + } else { + glog.Info("Updating doc artifact") + existing, err := serv.GetArtifactById(*da.Id) + if err != nil { + return nil, err + } + if existing.DocArtifact == nil { + return nil, fmt.Errorf("mismatched types, artifact with id %s is not a doc artifact", *da.Id) + } + + withNotEditable, err := serv.openapiConv.OverrideNotEditableForDocArtifact(converter.NewOpenapiUpdateWrapper(existing.DocArtifact, da)) + if err != nil { + return nil, err + } + da = &withNotEditable + + _, err = serv.getModelVersionByArtifactId(*da.Id) + if err != nil { + return nil, err + } } } else { - // update - glog.Infof("Updating model artifact %s", *modelArtifact.Id) - existing, err = serv.GetModelArtifactById(*modelArtifact.Id) - if err != nil { - return nil, err - } - - withNotEditable, err := serv.openapiConv.OverrideNotEditableForModelArtifact(converter.NewOpenapiUpdateWrapper(existing, modelArtifact)) - if err != nil { - return nil, err - } - modelArtifact = &withNotEditable - - _, err = serv.getModelVersionByArtifactId(*modelArtifact.Id) - if err != nil { - return nil, err - } + return nil, fmt.Errorf("invalid artifact type, must be either ModelArtifact or DocArtifact") } - - artifact, err := serv.mapper.MapFromModelArtifact(modelArtifact, modelVersionId) + pa, err := serv.mapper.MapFromArtifact(artifact, modelVersionId) if err != nil { return nil, err } - artifactsResp, err := serv.mlmdClient.PutArtifacts(context.Background(), &proto.PutArtifactsRequest{ - Artifacts: []*proto.Artifact{artifact}, + Artifacts: []*proto.Artifact{pa}, }) if err != nil { return nil, err } - // add explicit Attribution between Artifact and ModelVersion - if modelVersionId != nil && modelArtifact.Id == nil { + if creating { + // add explicit Attribution between Artifact and ModelVersion modelVersionId, err := converter.StringToInt64(modelVersionId) if err != nil { return nil, err @@ -617,15 +660,10 @@ func (serv *ModelRegistryService) UpsertModelArtifact(modelArtifact *openapi.Mod } idAsString := converter.Int64ToString(&artifactsResp.ArtifactIds[0]) - mapped, err := serv.GetModelArtifactById(*idAsString) - if err != nil { - return nil, err - } - return mapped, nil + return serv.GetArtifactById(*idAsString) } -// GetModelArtifactById retrieves a model artifact by its unique identifier (ID). -func (serv *ModelRegistryService) GetModelArtifactById(id string) (*openapi.ModelArtifact, error) { +func (serv *ModelRegistryService) GetArtifactById(id string) (*openapi.Artifact, error) { idAsInt, err := converter.StringToInt64(&id) if err != nil { return nil, err @@ -637,26 +675,88 @@ func (serv *ModelRegistryService) GetModelArtifactById(id string) (*openapi.Mode if err != nil { return nil, err } - if len(artifactsResp.Artifacts) > 1 { - return nil, fmt.Errorf("multiple model artifacts found for id %s", id) + return nil, fmt.Errorf("multiple artifacts found for id %s", id) } - if len(artifactsResp.Artifacts) == 0 { - return nil, fmt.Errorf("no model artifact found for id %s", id) + return nil, fmt.Errorf("no artifact found for id %s", id) + } + return serv.mapper.MapToArtifact(artifactsResp.Artifacts[0]) +} + +func (serv *ModelRegistryService) GetArtifacts(listOptions api.ListOptions, modelVersionId *string) (*openapi.ArtifactList, error) { + listOperationOptions, err := apiutils.BuildListOperationOptions(listOptions) + if err != nil { + return nil, err + } + var artifacts []*proto.Artifact + var nextPageToken *string + if modelVersionId == nil { + return nil, fmt.Errorf("missing model version id, cannot get artifacts without model version") + } + ctxId, err := converter.StringToInt64(modelVersionId) + if err != nil { + return nil, err + } + artifactsResp, err := serv.mlmdClient.GetArtifactsByContext(context.Background(), &proto.GetArtifactsByContextRequest{ + ContextId: ctxId, + Options: listOperationOptions, + }) + if err != nil { + return nil, err + } + artifacts = artifactsResp.Artifacts + nextPageToken = artifactsResp.NextPageToken + + results := []openapi.Artifact{} + for _, a := range artifacts { + mapped, err := serv.mapper.MapToArtifact(a) + if err != nil { + return nil, err + } + results = append(results, *mapped) + } + + toReturn := openapi.ArtifactList{ + NextPageToken: apiutils.ZeroIfNil(nextPageToken), + PageSize: apiutils.ZeroIfNil(listOptions.PageSize), + Size: int32(len(results)), + Items: results, } + return &toReturn, nil +} - result, err := serv.mapper.MapToModelArtifact(artifactsResp.Artifacts[0]) +// MODEL ARTIFACTS + +// UpsertModelArtifact creates a new model artifact if the provided model artifact's ID is nil, +// or updates an existing model artifact if the ID is provided. +// If a model version ID is provided and the model artifact is newly created, establishes an +// explicit attribution between the model version and the created model artifact. +func (serv *ModelRegistryService) UpsertModelArtifact(modelArtifact *openapi.ModelArtifact, modelVersionId *string) (*openapi.ModelArtifact, error) { + art, err := serv.UpsertArtifact(&openapi.Artifact{ + ModelArtifact: modelArtifact, + }, modelVersionId) if err != nil { return nil, err } + return art.ModelArtifact, err +} - return result, nil +// GetModelArtifactById retrieves a model artifact by its unique identifier (ID). +func (serv *ModelRegistryService) GetModelArtifactById(id string) (*openapi.ModelArtifact, error) { + art, err := serv.GetArtifactById(id) + if err != nil { + return nil, err + } + ma := art.ModelArtifact + if ma == nil { + return nil, fmt.Errorf("artifact with id %s is not a model artifact", id) + } + return ma, err } // GetModelArtifactByInferenceService retrieves the model artifact associated with the specified inference service ID. func (serv *ModelRegistryService) GetModelArtifactByInferenceService(inferenceServiceId string) (*openapi.ModelArtifact, error) { - mv, err := serv.GetModelVersionByInferenceService(inferenceServiceId) if err != nil { return nil, err @@ -992,7 +1092,8 @@ func (serv *ModelRegistryService) UpsertInferenceService(inferenceService *opena _, err = serv.mlmdClient.PutParentContexts(context.Background(), &proto.PutParentContextsRequest{ ParentContexts: []*proto.ParentContext{{ ChildId: inferenceServiceId, - ParentId: servingEnvironmentId}}, + ParentId: servingEnvironmentId, + }}, TransactionOptions: &proto.TransactionOptions{}, }) if err != nil { diff --git a/pkg/core/core_test.go b/pkg/core/core_test.go index e4473253..a031c541 100644 --- a/pkg/core/core_test.go +++ b/pkg/core/core_test.go @@ -53,9 +53,7 @@ type CoreTestSuite struct { mlmdClient proto.MetadataStoreServiceClient } -var ( - canAddFields = apiutils.Of(true) -) +var canAddFields = apiutils.Of(true) func TestRunCoreTestSuite(t *testing.T) { // before all @@ -257,6 +255,12 @@ func (suite *CoreTestSuite) TestModelRegistryStartupWithExistingEmptyTypes() { Name: modelVersionTypeName, }, } + docArtifactReq := proto.PutArtifactTypeRequest{ + CanAddFields: canAddFields, + ArtifactType: &proto.ArtifactType{ + Name: docArtifactTypeName, + }, + } modelArtifactReq := proto.PutArtifactTypeRequest{ CanAddFields: canAddFields, ArtifactType: &proto.ArtifactType{ @@ -286,6 +290,8 @@ func (suite *CoreTestSuite) TestModelRegistryStartupWithExistingEmptyTypes() { suite.Nil(err) _, err = suite.mlmdClient.PutContextType(context.Background(), &modelVersionReq) suite.Nil(err) + _, err = suite.mlmdClient.PutArtifactType(context.Background(), &docArtifactReq) + suite.Nil(err) _, err = suite.mlmdClient.PutArtifactType(context.Background(), &modelArtifactReq) suite.Nil(err) _, err = suite.mlmdClient.PutContextType(context.Background(), &servingEnvironmentReq) @@ -302,6 +308,9 @@ func (suite *CoreTestSuite) TestModelRegistryStartupWithExistingEmptyTypes() { modelVersionResp, _ := suite.mlmdClient.GetContextType(ctx, &proto.GetContextTypeRequest{ TypeName: modelVersionTypeName, }) + docArtifactResp, _ := suite.mlmdClient.GetArtifactType(ctx, &proto.GetArtifactTypeRequest{ + TypeName: docArtifactTypeName, + }) modelArtifactResp, _ := suite.mlmdClient.GetArtifactType(ctx, &proto.GetArtifactTypeRequest{ TypeName: modelArtifactTypeName, }) @@ -317,6 +326,7 @@ func (suite *CoreTestSuite) TestModelRegistryStartupWithExistingEmptyTypes() { suite.Equal(0, len(regModelResp.ContextType.Properties)) suite.Equal(0, len(modelVersionResp.ContextType.Properties)) + suite.Equal(0, len(docArtifactResp.ArtifactType.Properties)) suite.Equal(0, len(modelArtifactResp.ArtifactType.Properties)) suite.Equal(0, len(servingEnvResp.ContextType.Properties)) suite.Equal(0, len(inferenceServiceResp.ContextType.Properties)) @@ -341,6 +351,13 @@ func (suite *CoreTestSuite) TestModelRegistryStartupWithExistingEmptyTypes() { suite.Equal(*modelVersionTypeName, *modelVersionResp.ContextType.Name) suite.Equal(5, len(modelVersionResp.ContextType.Properties)) + docArtifactResp, _ = suite.mlmdClient.GetArtifactType(ctx, &proto.GetArtifactTypeRequest{ + TypeName: docArtifactTypeName, + }) + suite.NotNilf(docArtifactResp.ArtifactType, "doc artifact type %s should exists", *docArtifactTypeName) + suite.Equal(*docArtifactTypeName, *docArtifactResp.ArtifactType.Name) + suite.Equal(1, len(docArtifactResp.ArtifactType.Properties)) + modelArtifactResp, _ = suite.mlmdClient.GetArtifactType(ctx, &proto.GetArtifactTypeRequest{ TypeName: modelArtifactTypeName, }) @@ -388,10 +405,16 @@ func (suite *CoreTestSuite) TestModelRegistryTypes() { suite.NotNilf(modelVersionResp.ContextType, "model version type %s should exists", *modelVersionTypeName) suite.Equal(*modelVersionTypeName, *modelVersionResp.ContextType.Name) + docArtifactResp, _ := suite.mlmdClient.GetArtifactType(ctx, &proto.GetArtifactTypeRequest{ + TypeName: docArtifactTypeName, + }) + suite.NotNilf(docArtifactResp.ArtifactType, "doc artifact type %s should exists", *docArtifactTypeName) + suite.Equal(*docArtifactTypeName, *docArtifactResp.ArtifactType.Name) + modelArtifactResp, _ := suite.mlmdClient.GetArtifactType(ctx, &proto.GetArtifactTypeRequest{ TypeName: modelArtifactTypeName, }) - suite.NotNilf(modelArtifactResp.ArtifactType, "model version type %s should exists", *modelArtifactTypeName) + suite.NotNilf(modelArtifactResp.ArtifactType, "model artifact type %s should exists", *modelArtifactTypeName) suite.Equal(*modelArtifactTypeName, *modelArtifactResp.ArtifactType.Name) servingEnvResp, _ := suite.mlmdClient.GetContextType(ctx, &proto.GetContextTypeRequest{ @@ -1345,6 +1368,251 @@ func (suite *CoreTestSuite) TestGetModelVersions() { suite.Equal(*converter.Int64ToString(createdVersionId3), *getAllByRegModel.Items[1].Id) } +// ARTIFACTS + +func (suite *CoreTestSuite) TestCreateArtifact() { + // create mode registry service + service := suite.setupModelRegistryService() + + modelVersionId := suite.registerModelVersion(service, nil, nil, nil, nil) + + createdArt, err := service.UpsertArtifact(&openapi.Artifact{ + DocArtifact: &openapi.DocArtifact{ + Name: &artifactName, + State: (*openapi.ArtifactState)(&artifactState), + Uri: &artifactUri, + Description: &artifactDescription, + CustomProperties: &map[string]openapi.MetadataValue{ + "custom_string_prop": { + MetadataStringValue: &openapi.MetadataStringValue{ + StringValue: &customString, + }, + }, + }, + }, + }, &modelVersionId) + suite.Nilf(err, "error creating new artifact for %d: %v", modelVersionId, err) + + docArtifact := createdArt.DocArtifact + suite.NotNilf(docArtifact, "error creating new artifact for %d", modelVersionId) + state, _ := openapi.NewArtifactStateFromValue(artifactState) + suite.NotNil(docArtifact.Id, "created artifact id should not be nil") + suite.Equal(artifactName, *docArtifact.Name) + suite.Equal(*state, *docArtifact.State) + suite.Equal(artifactUri, *docArtifact.Uri) + suite.Equal(artifactDescription, *docArtifact.Description) + suite.Equal(customString, *(*docArtifact.CustomProperties)["custom_string_prop"].MetadataStringValue.StringValue) +} + +func (suite *CoreTestSuite) TestCreateArtifactFailure() { + // create mode registry service + service := suite.setupModelRegistryService() + + modelVersionId := "9998" + + var artifact openapi.Artifact + artifact.DocArtifact = &openapi.DocArtifact{ + Name: &artifactName, + State: (*openapi.ArtifactState)(&artifactState), + Uri: &artifactUri, + CustomProperties: &map[string]openapi.MetadataValue{ + "custom_string_prop": { + MetadataStringValue: &openapi.MetadataStringValue{ + StringValue: &customString, + }, + }, + }, + } + + _, err := service.UpsertArtifact(&artifact, nil) + suite.NotNil(err) + suite.Equal("missing model version id, cannot create artifact without model version", err.Error()) + + _, err = service.UpsertArtifact(&artifact, &modelVersionId) + suite.NotNil(err) + suite.Equal("no model version found for id 9998", err.Error()) +} + +func (suite *CoreTestSuite) TestUpdateArtifact() { + // create mode registry service + service := suite.setupModelRegistryService() + + modelVersionId := suite.registerModelVersion(service, nil, nil, nil, nil) + + createdArtifact, err := service.UpsertArtifact(&openapi.Artifact{ + DocArtifact: &openapi.DocArtifact{ + Name: &artifactName, + State: (*openapi.ArtifactState)(&artifactState), + Uri: &artifactUri, + CustomProperties: &map[string]openapi.MetadataValue{ + "custom_string_prop": { + MetadataStringValue: &openapi.MetadataStringValue{ + StringValue: &customString, + }, + }, + }, + }, + }, &modelVersionId) + suite.Nilf(err, "error creating new artifact for %d", modelVersionId) + + newState := "MARKED_FOR_DELETION" + createdArtifact.DocArtifact.State = (*openapi.ArtifactState)(&newState) + updatedArtifact, err := service.UpsertArtifact(createdArtifact, &modelVersionId) + suite.Nilf(err, "error updating artifact for %d: %v", modelVersionId, err) + + createdArtifactId, _ := converter.StringToInt64(createdArtifact.DocArtifact.Id) + updatedArtifactId, _ := converter.StringToInt64(updatedArtifact.DocArtifact.Id) + suite.Equal(createdArtifactId, updatedArtifactId) + + getById, err := suite.mlmdClient.GetArtifactsByID(context.Background(), &proto.GetArtifactsByIDRequest{ + ArtifactIds: []int64{*createdArtifactId}, + }) + suite.Nilf(err, "error getting artifact by id %d", createdArtifactId) + + suite.Equal(*createdArtifactId, *getById.Artifacts[0].Id) + suite.Equal(fmt.Sprintf("%s:%s", modelVersionId, *createdArtifact.DocArtifact.Name), *getById.Artifacts[0].Name) + suite.Equal(string(newState), getById.Artifacts[0].State.String()) + suite.Equal(*createdArtifact.DocArtifact.Uri, *getById.Artifacts[0].Uri) + suite.Equal(*(*createdArtifact.DocArtifact.CustomProperties)["custom_string_prop"].MetadataStringValue.StringValue, getById.Artifacts[0].CustomProperties["custom_string_prop"].GetStringValue()) +} + +func (suite *CoreTestSuite) TestUpdateArtifactFailure() { + // create mode registry service + service := suite.setupModelRegistryService() + + modelVersionId := suite.registerModelVersion(service, nil, nil, nil, nil) + + createdArtifact, err := service.UpsertArtifact(&openapi.Artifact{ + DocArtifact: &openapi.DocArtifact{ + Name: &artifactName, + State: (*openapi.ArtifactState)(&artifactState), + Uri: &artifactUri, + CustomProperties: &map[string]openapi.MetadataValue{ + "custom_string_prop": { + MetadataStringValue: &openapi.MetadataStringValue{ + StringValue: &customString, + }, + }, + }, + }, + }, &modelVersionId) + suite.Nilf(err, "error creating new artifact for model version %s", modelVersionId) + suite.NotNilf(createdArtifact.DocArtifact.Id, "created model artifact should not have nil Id") + + newState := "MARKED_FOR_DELETION" + createdArtifact.DocArtifact.State = (*openapi.ArtifactState)(&newState) + updatedArtifact, err := service.UpsertArtifact(createdArtifact, &modelVersionId) + suite.Nilf(err, "error updating artifact for %d: %v", modelVersionId, err) + + wrongId := "5555" + updatedArtifact.DocArtifact.Id = &wrongId + _, err = service.UpsertArtifact(updatedArtifact, &modelVersionId) + suite.NotNil(err) + suite.Equal(fmt.Sprintf("no artifact found for id %s", wrongId), err.Error()) +} + +func (suite *CoreTestSuite) TestGetArtifactById() { + // create mode registry service + service := suite.setupModelRegistryService() + + modelVersionId := suite.registerModelVersion(service, nil, nil, nil, nil) + + createdArtifact, err := service.UpsertArtifact(&openapi.Artifact{ + DocArtifact: &openapi.DocArtifact{ + Name: &artifactName, + State: (*openapi.ArtifactState)(&artifactState), + Uri: &artifactUri, + CustomProperties: &map[string]openapi.MetadataValue{ + "custom_string_prop": { + MetadataStringValue: &openapi.MetadataStringValue{ + StringValue: &customString, + }, + }, + }, + }, + }, &modelVersionId) + suite.Nilf(err, "error creating new model artifact for %d", modelVersionId) + + createdArtifactId, _ := converter.StringToInt64(createdArtifact.DocArtifact.Id) + + getById, err := service.GetArtifactById(*createdArtifact.DocArtifact.Id) + suite.Nilf(err, "error getting artifact by id %d", createdArtifactId) + + state, _ := openapi.NewArtifactStateFromValue(artifactState) + suite.NotNil(createdArtifact.DocArtifact.Id, "created artifact id should not be nil") + suite.Equal(artifactName, *getById.DocArtifact.Name) + suite.Equal(*state, *getById.DocArtifact.State) + suite.Equal(artifactUri, *getById.DocArtifact.Uri) + suite.Equal(customString, *(*getById.DocArtifact.CustomProperties)["custom_string_prop"].MetadataStringValue.StringValue) + + suite.Equal(*createdArtifact, *getById, "artifacts returned during creation and on get by id should be equal") +} + +func (suite *CoreTestSuite) TestGetArtifacts() { + // create mode registry service + service := suite.setupModelRegistryService() + + modelVersionId := suite.registerModelVersion(service, nil, nil, nil, nil) + + secondArtifactName := "second-name" + secondArtifactExtId := "second-ext-id" + secondArtifactUri := "second-uri" + + createdArtifact1, err := service.UpsertArtifact(&openapi.Artifact{ + ModelArtifact: &openapi.ModelArtifact{ + Name: &artifactName, + State: (*openapi.ArtifactState)(&artifactState), + Uri: &artifactUri, + ExternalID: &artifactExtId, + CustomProperties: &map[string]openapi.MetadataValue{ + "custom_string_prop": { + MetadataStringValue: &openapi.MetadataStringValue{ + StringValue: &customString, + }, + }, + }, + }, + }, &modelVersionId) + suite.Nilf(err, "error creating new artifact for %d", modelVersionId) + createdArtifact2, err := service.UpsertArtifact(&openapi.Artifact{ + DocArtifact: &openapi.DocArtifact{ + Name: &secondArtifactName, + State: (*openapi.ArtifactState)(&artifactState), + Uri: &secondArtifactUri, + ExternalID: &secondArtifactExtId, + CustomProperties: &map[string]openapi.MetadataValue{ + "custom_string_prop": { + MetadataStringValue: &openapi.MetadataStringValue{ + StringValue: &customString, + }, + }, + }, + }, + }, &modelVersionId) + suite.Nilf(err, "error creating new artifact for %d", modelVersionId) + + createdArtifactId1, _ := converter.StringToInt64(createdArtifact1.ModelArtifact.Id) + createdArtifactId2, _ := converter.StringToInt64(createdArtifact2.DocArtifact.Id) + + getAll, err := service.GetArtifacts(api.ListOptions{}, &modelVersionId) + suite.Nilf(err, "error getting all model artifacts") + suite.Equalf(int32(2), getAll.Size, "expected two artifacts") + + suite.Equal(*converter.Int64ToString(createdArtifactId1), *getAll.Items[0].ModelArtifact.Id) + suite.Equal(*converter.Int64ToString(createdArtifactId2), *getAll.Items[1].DocArtifact.Id) + + orderByLastUpdate := "LAST_UPDATE_TIME" + getAllByModelVersion, err := service.GetArtifacts(api.ListOptions{ + OrderBy: &orderByLastUpdate, + SortOrder: &descOrderDirection, + }, &modelVersionId) + suite.Nilf(err, "error getting all model artifacts for %d", modelVersionId) + suite.Equalf(int32(2), getAllByModelVersion.Size, "expected 2 artifacts for model version %d", modelVersionId) + + suite.Equal(*converter.Int64ToString(createdArtifactId1), *getAllByModelVersion.Items[1].ModelArtifact.Id) + suite.Equal(*converter.Int64ToString(createdArtifactId2), *getAllByModelVersion.Items[0].DocArtifact.Id) +} + // MODEL ARTIFACTS func (suite *CoreTestSuite) TestCreateModelArtifact() { @@ -1353,7 +1621,7 @@ func (suite *CoreTestSuite) TestCreateModelArtifact() { modelVersionId := suite.registerModelVersion(service, nil, nil, nil, nil) - modelArtifact := &openapi.ModelArtifact{ + modelArtifact, err := service.UpsertModelArtifact(&openapi.ModelArtifact{ Name: &artifactName, State: (*openapi.ArtifactState)(&artifactState), Uri: &artifactUri, @@ -1369,46 +1637,20 @@ func (suite *CoreTestSuite) TestCreateModelArtifact() { }, }, }, - } - - createdArtifact, err := service.UpsertModelArtifact(modelArtifact, &modelVersionId) + }, &modelVersionId) suite.Nilf(err, "error creating new model artifact for %d", modelVersionId) state, _ := openapi.NewArtifactStateFromValue(artifactState) - suite.NotNil(createdArtifact.Id, "created artifact id should not be nil") - suite.Equal(artifactName, *createdArtifact.Name) - suite.Equal(*state, *createdArtifact.State) - suite.Equal(artifactUri, *createdArtifact.Uri) - suite.Equal(artifactDescription, *createdArtifact.Description) - suite.Equal("onnx", *createdArtifact.ModelFormatName) - suite.Equal("1", *createdArtifact.ModelFormatVersion) - suite.Equal("aws-connection-models", *createdArtifact.StorageKey) - suite.Equal("bucket", *createdArtifact.StoragePath) - suite.Equal(customString, *(*createdArtifact.CustomProperties)["custom_string_prop"].MetadataStringValue.StringValue) - - createdArtifactId, _ := converter.StringToInt64(createdArtifact.Id) - getById, err := suite.mlmdClient.GetArtifactsByID(context.Background(), &proto.GetArtifactsByIDRequest{ - ArtifactIds: []int64{*createdArtifactId}, - }) - suite.Nilf(err, "error getting model artifact by id %d", createdArtifactId) - - suite.Equal(*createdArtifactId, *getById.Artifacts[0].Id) - suite.Equal(fmt.Sprintf("%s:%s", modelVersionId, *createdArtifact.Name), *getById.Artifacts[0].Name) - suite.Equal(string(*createdArtifact.State), getById.Artifacts[0].State.String()) - suite.Equal(*createdArtifact.Uri, *getById.Artifacts[0].Uri) - suite.Equal(*createdArtifact.Description, getById.Artifacts[0].Properties["description"].GetStringValue()) - suite.Equal(*createdArtifact.ModelFormatName, getById.Artifacts[0].Properties["model_format_name"].GetStringValue()) - suite.Equal(*createdArtifact.ModelFormatVersion, getById.Artifacts[0].Properties["model_format_version"].GetStringValue()) - suite.Equal(*createdArtifact.StorageKey, getById.Artifacts[0].Properties["storage_key"].GetStringValue()) - suite.Equal(*createdArtifact.StoragePath, getById.Artifacts[0].Properties["storage_path"].GetStringValue()) - suite.Equal(*(*createdArtifact.CustomProperties)["custom_string_prop"].MetadataStringValue.StringValue, getById.Artifacts[0].CustomProperties["custom_string_prop"].GetStringValue()) - - modelVersionIdAsInt, _ := converter.StringToInt64(&modelVersionId) - byCtx, _ := suite.mlmdClient.GetArtifactsByContext(context.Background(), &proto.GetArtifactsByContextRequest{ - ContextId: (*int64)(modelVersionIdAsInt), - }) - suite.Equal(1, len(byCtx.Artifacts)) - suite.Equal(*createdArtifactId, *byCtx.Artifacts[0].Id) + suite.NotNil(modelArtifact.Id, "created artifact id should not be nil") + suite.Equal(artifactName, *modelArtifact.Name) + suite.Equal(*state, *modelArtifact.State) + suite.Equal(artifactUri, *modelArtifact.Uri) + suite.Equal(artifactDescription, *modelArtifact.Description) + suite.Equal("onnx", *modelArtifact.ModelFormatName) + suite.Equal("1", *modelArtifact.ModelFormatVersion) + suite.Equal("aws-connection-models", *modelArtifact.StorageKey) + suite.Equal("bucket", *modelArtifact.StoragePath) + suite.Equal(customString, *(*modelArtifact.CustomProperties)["custom_string_prop"].MetadataStringValue.StringValue) } func (suite *CoreTestSuite) TestCreateModelArtifactFailure() { @@ -1432,7 +1674,7 @@ func (suite *CoreTestSuite) TestCreateModelArtifactFailure() { _, err := service.UpsertModelArtifact(modelArtifact, nil) suite.NotNil(err) - suite.Equal("missing model version id, cannot create model artifact without model version", err.Error()) + suite.Equal("missing model version id, cannot create artifact without model version", err.Error()) _, err = service.UpsertModelArtifact(modelArtifact, &modelVersionId) suite.NotNil(err) @@ -1504,17 +1746,6 @@ func (suite *CoreTestSuite) TestUpdateModelArtifactFailure() { createdArtifact, err := service.UpsertModelArtifact(modelArtifact, &modelVersionId) suite.Nilf(err, "error creating new model artifact for model version %s", modelVersionId) suite.NotNilf(createdArtifact.Id, "created model artifact should not have nil Id") - - newState := "MARKED_FOR_DELETION" - createdArtifact.State = (*openapi.ArtifactState)(&newState) - updatedArtifact, err := service.UpsertModelArtifact(createdArtifact, &modelVersionId) - suite.Nilf(err, "error updating model artifact for %d: %v", modelVersionId, err) - - wrongId := "9998" - updatedArtifact.Id = &wrongId - _, err = service.UpsertModelArtifact(updatedArtifact, &modelVersionId) - suite.NotNil(err) - suite.Equal(fmt.Sprintf("no model artifact found for id %s", wrongId), err.Error()) } func (suite *CoreTestSuite) TestGetModelArtifactById() { diff --git a/pkg/openapi/.openapi-generator/FILES b/pkg/openapi/.openapi-generator/FILES index 6f119555..ba72484a 100644 --- a/pkg/openapi/.openapi-generator/FILES +++ b/pkg/openapi/.openapi-generator/FILES @@ -14,6 +14,7 @@ model_base_resource.go model_base_resource_create.go model_base_resource_list.go model_base_resource_update.go +model_doc_artifact.go model_error.go model_execution_state.go model_inference_service.go diff --git a/pkg/openapi/api_model_registry_service.go b/pkg/openapi/api_model_registry_service.go index 91826b6e..087ce1e6 100644 --- a/pkg/openapi/api_model_registry_service.go +++ b/pkg/openapi/api_model_registry_service.go @@ -3682,9 +3682,7 @@ func (r ApiGetModelVersionArtifactsRequest) Execute() (*ArtifactList, *http.Resp } /* -GetModelVersionArtifacts List All ModelVersion's artifacts - -Gets a list of all `Artifact` entities for the `ModelVersion`. +GetModelVersionArtifacts List all artifacts associated with the `ModelVersion` @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @param modelversionId A unique identifier for a `ModelVersion`. diff --git a/pkg/openapi/model_artifact.go b/pkg/openapi/model_artifact.go index 43b8f85b..143a29c8 100644 --- a/pkg/openapi/model_artifact.go +++ b/pkg/openapi/model_artifact.go @@ -17,9 +17,17 @@ import ( // Artifact - A metadata Artifact Entity. type Artifact struct { + DocArtifact *DocArtifact ModelArtifact *ModelArtifact } +// DocArtifactAsArtifact is a convenience function that returns DocArtifact wrapped in Artifact +func DocArtifactAsArtifact(v *DocArtifact) Artifact { + return Artifact{ + DocArtifact: v, + } +} + // ModelArtifactAsArtifact is a convenience function that returns ModelArtifact wrapped in Artifact func ModelArtifactAsArtifact(v *ModelArtifact) Artifact { return Artifact{ @@ -37,6 +45,18 @@ func (dst *Artifact) UnmarshalJSON(data []byte) error { return fmt.Errorf("failed to unmarshal JSON into map for the discriminator lookup") } + // check if the discriminator value is 'DocArtifact' + if jsonDict["artifactType"] == "DocArtifact" { + // try to unmarshal JSON data into DocArtifact + err = json.Unmarshal(data, &dst.DocArtifact) + if err == nil { + return nil // data stored in dst.DocArtifact, return on the first match + } else { + dst.DocArtifact = nil + return fmt.Errorf("failed to unmarshal Artifact as DocArtifact: %s", err.Error()) + } + } + // check if the discriminator value is 'ModelArtifact' if jsonDict["artifactType"] == "ModelArtifact" { // try to unmarshal JSON data into ModelArtifact @@ -49,6 +69,18 @@ func (dst *Artifact) UnmarshalJSON(data []byte) error { } } + // check if the discriminator value is 'doc-artifact' + if jsonDict["artifactType"] == "doc-artifact" { + // try to unmarshal JSON data into DocArtifact + err = json.Unmarshal(data, &dst.DocArtifact) + if err == nil { + return nil // data stored in dst.DocArtifact, return on the first match + } else { + dst.DocArtifact = nil + return fmt.Errorf("failed to unmarshal Artifact as DocArtifact: %s", err.Error()) + } + } + // check if the discriminator value is 'model-artifact' if jsonDict["artifactType"] == "model-artifact" { // try to unmarshal JSON data into ModelArtifact @@ -66,6 +98,10 @@ func (dst *Artifact) UnmarshalJSON(data []byte) error { // Marshal data from the first non-nil pointers in the struct to JSON func (src Artifact) MarshalJSON() ([]byte, error) { + if src.DocArtifact != nil { + return json.Marshal(&src.DocArtifact) + } + if src.ModelArtifact != nil { return json.Marshal(&src.ModelArtifact) } @@ -78,6 +114,10 @@ func (obj *Artifact) GetActualInstance() interface{} { if obj == nil { return nil } + if obj.DocArtifact != nil { + return obj.DocArtifact + } + if obj.ModelArtifact != nil { return obj.ModelArtifact } diff --git a/pkg/openapi/model_doc_artifact.go b/pkg/openapi/model_doc_artifact.go new file mode 100644 index 00000000..28e36697 --- /dev/null +++ b/pkg/openapi/model_doc_artifact.go @@ -0,0 +1,453 @@ +/* +Model Registry REST API + +REST API for Model Registry to create and manage ML model metadata + +API version: v1alpha1 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// checks if the DocArtifact type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &DocArtifact{} + +// DocArtifact A document. +type DocArtifact struct { + // User provided custom properties which are not defined by its type. + CustomProperties *map[string]MetadataValue `json:"customProperties,omitempty"` + // An optional description about the resource. + Description *string `json:"description,omitempty"` + // The external id that come from the clients’ system. This field is optional. If set, it must be unique among all resources within a database instance. + ExternalID *string `json:"externalID,omitempty"` + // The uniform resource identifier of the physical artifact. May be empty if there is no physical artifact. + Uri *string `json:"uri,omitempty"` + State *ArtifactState `json:"state,omitempty"` + // The client provided name of the artifact. This field is optional. If set, it must be unique among all the artifacts of the same artifact type within a database instance and cannot be changed once set. + Name *string `json:"name,omitempty"` + // Output only. The unique server generated id of the resource. + Id *string `json:"id,omitempty"` + // Output only. Create time of the resource in millisecond since epoch. + CreateTimeSinceEpoch *string `json:"createTimeSinceEpoch,omitempty"` + // Output only. Last update time of the resource since epoch in millisecond since epoch. + LastUpdateTimeSinceEpoch *string `json:"lastUpdateTimeSinceEpoch,omitempty"` + ArtifactType string `json:"artifactType"` +} + +// NewDocArtifact instantiates a new DocArtifact object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewDocArtifact(artifactType string) *DocArtifact { + this := DocArtifact{} + var state ArtifactState = ARTIFACTSTATE_UNKNOWN + this.State = &state + this.ArtifactType = artifactType + return &this +} + +// NewDocArtifactWithDefaults instantiates a new DocArtifact object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewDocArtifactWithDefaults() *DocArtifact { + this := DocArtifact{} + var state ArtifactState = ARTIFACTSTATE_UNKNOWN + this.State = &state + var artifactType string = "doc-artifact" + this.ArtifactType = artifactType + return &this +} + +// GetCustomProperties returns the CustomProperties field value if set, zero value otherwise. +func (o *DocArtifact) GetCustomProperties() map[string]MetadataValue { + if o == nil || IsNil(o.CustomProperties) { + var ret map[string]MetadataValue + return ret + } + return *o.CustomProperties +} + +// GetCustomPropertiesOk returns a tuple with the CustomProperties field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DocArtifact) GetCustomPropertiesOk() (*map[string]MetadataValue, bool) { + if o == nil || IsNil(o.CustomProperties) { + return nil, false + } + return o.CustomProperties, true +} + +// HasCustomProperties returns a boolean if a field has been set. +func (o *DocArtifact) HasCustomProperties() bool { + if o != nil && !IsNil(o.CustomProperties) { + return true + } + + return false +} + +// SetCustomProperties gets a reference to the given map[string]MetadataValue and assigns it to the CustomProperties field. +func (o *DocArtifact) SetCustomProperties(v map[string]MetadataValue) { + o.CustomProperties = &v +} + +// GetDescription returns the Description field value if set, zero value otherwise. +func (o *DocArtifact) GetDescription() string { + if o == nil || IsNil(o.Description) { + var ret string + return ret + } + return *o.Description +} + +// GetDescriptionOk returns a tuple with the Description field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DocArtifact) GetDescriptionOk() (*string, bool) { + if o == nil || IsNil(o.Description) { + return nil, false + } + return o.Description, true +} + +// HasDescription returns a boolean if a field has been set. +func (o *DocArtifact) HasDescription() bool { + if o != nil && !IsNil(o.Description) { + return true + } + + return false +} + +// SetDescription gets a reference to the given string and assigns it to the Description field. +func (o *DocArtifact) SetDescription(v string) { + o.Description = &v +} + +// GetExternalID returns the ExternalID field value if set, zero value otherwise. +func (o *DocArtifact) GetExternalID() string { + if o == nil || IsNil(o.ExternalID) { + var ret string + return ret + } + return *o.ExternalID +} + +// GetExternalIDOk returns a tuple with the ExternalID field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DocArtifact) GetExternalIDOk() (*string, bool) { + if o == nil || IsNil(o.ExternalID) { + return nil, false + } + return o.ExternalID, true +} + +// HasExternalID returns a boolean if a field has been set. +func (o *DocArtifact) HasExternalID() bool { + if o != nil && !IsNil(o.ExternalID) { + return true + } + + return false +} + +// SetExternalID gets a reference to the given string and assigns it to the ExternalID field. +func (o *DocArtifact) SetExternalID(v string) { + o.ExternalID = &v +} + +// GetUri returns the Uri field value if set, zero value otherwise. +func (o *DocArtifact) GetUri() string { + if o == nil || IsNil(o.Uri) { + var ret string + return ret + } + return *o.Uri +} + +// GetUriOk returns a tuple with the Uri field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DocArtifact) GetUriOk() (*string, bool) { + if o == nil || IsNil(o.Uri) { + return nil, false + } + return o.Uri, true +} + +// HasUri returns a boolean if a field has been set. +func (o *DocArtifact) HasUri() bool { + if o != nil && !IsNil(o.Uri) { + return true + } + + return false +} + +// SetUri gets a reference to the given string and assigns it to the Uri field. +func (o *DocArtifact) SetUri(v string) { + o.Uri = &v +} + +// GetState returns the State field value if set, zero value otherwise. +func (o *DocArtifact) GetState() ArtifactState { + if o == nil || IsNil(o.State) { + var ret ArtifactState + return ret + } + return *o.State +} + +// GetStateOk returns a tuple with the State field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DocArtifact) GetStateOk() (*ArtifactState, bool) { + if o == nil || IsNil(o.State) { + return nil, false + } + return o.State, true +} + +// HasState returns a boolean if a field has been set. +func (o *DocArtifact) HasState() bool { + if o != nil && !IsNil(o.State) { + return true + } + + return false +} + +// SetState gets a reference to the given ArtifactState and assigns it to the State field. +func (o *DocArtifact) SetState(v ArtifactState) { + o.State = &v +} + +// GetName returns the Name field value if set, zero value otherwise. +func (o *DocArtifact) GetName() string { + if o == nil || IsNil(o.Name) { + var ret string + return ret + } + return *o.Name +} + +// GetNameOk returns a tuple with the Name field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DocArtifact) GetNameOk() (*string, bool) { + if o == nil || IsNil(o.Name) { + return nil, false + } + return o.Name, true +} + +// HasName returns a boolean if a field has been set. +func (o *DocArtifact) HasName() bool { + if o != nil && !IsNil(o.Name) { + return true + } + + return false +} + +// SetName gets a reference to the given string and assigns it to the Name field. +func (o *DocArtifact) SetName(v string) { + o.Name = &v +} + +// GetId returns the Id field value if set, zero value otherwise. +func (o *DocArtifact) GetId() string { + if o == nil || IsNil(o.Id) { + var ret string + return ret + } + return *o.Id +} + +// GetIdOk returns a tuple with the Id field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DocArtifact) GetIdOk() (*string, bool) { + if o == nil || IsNil(o.Id) { + return nil, false + } + return o.Id, true +} + +// HasId returns a boolean if a field has been set. +func (o *DocArtifact) HasId() bool { + if o != nil && !IsNil(o.Id) { + return true + } + + return false +} + +// SetId gets a reference to the given string and assigns it to the Id field. +func (o *DocArtifact) SetId(v string) { + o.Id = &v +} + +// GetCreateTimeSinceEpoch returns the CreateTimeSinceEpoch field value if set, zero value otherwise. +func (o *DocArtifact) GetCreateTimeSinceEpoch() string { + if o == nil || IsNil(o.CreateTimeSinceEpoch) { + var ret string + return ret + } + return *o.CreateTimeSinceEpoch +} + +// GetCreateTimeSinceEpochOk returns a tuple with the CreateTimeSinceEpoch field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DocArtifact) GetCreateTimeSinceEpochOk() (*string, bool) { + if o == nil || IsNil(o.CreateTimeSinceEpoch) { + return nil, false + } + return o.CreateTimeSinceEpoch, true +} + +// HasCreateTimeSinceEpoch returns a boolean if a field has been set. +func (o *DocArtifact) HasCreateTimeSinceEpoch() bool { + if o != nil && !IsNil(o.CreateTimeSinceEpoch) { + return true + } + + return false +} + +// SetCreateTimeSinceEpoch gets a reference to the given string and assigns it to the CreateTimeSinceEpoch field. +func (o *DocArtifact) SetCreateTimeSinceEpoch(v string) { + o.CreateTimeSinceEpoch = &v +} + +// GetLastUpdateTimeSinceEpoch returns the LastUpdateTimeSinceEpoch field value if set, zero value otherwise. +func (o *DocArtifact) GetLastUpdateTimeSinceEpoch() string { + if o == nil || IsNil(o.LastUpdateTimeSinceEpoch) { + var ret string + return ret + } + return *o.LastUpdateTimeSinceEpoch +} + +// GetLastUpdateTimeSinceEpochOk returns a tuple with the LastUpdateTimeSinceEpoch field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *DocArtifact) GetLastUpdateTimeSinceEpochOk() (*string, bool) { + if o == nil || IsNil(o.LastUpdateTimeSinceEpoch) { + return nil, false + } + return o.LastUpdateTimeSinceEpoch, true +} + +// HasLastUpdateTimeSinceEpoch returns a boolean if a field has been set. +func (o *DocArtifact) HasLastUpdateTimeSinceEpoch() bool { + if o != nil && !IsNil(o.LastUpdateTimeSinceEpoch) { + return true + } + + return false +} + +// SetLastUpdateTimeSinceEpoch gets a reference to the given string and assigns it to the LastUpdateTimeSinceEpoch field. +func (o *DocArtifact) SetLastUpdateTimeSinceEpoch(v string) { + o.LastUpdateTimeSinceEpoch = &v +} + +// GetArtifactType returns the ArtifactType field value +func (o *DocArtifact) GetArtifactType() string { + if o == nil { + var ret string + return ret + } + + return o.ArtifactType +} + +// GetArtifactTypeOk returns a tuple with the ArtifactType field value +// and a boolean to check if the value has been set. +func (o *DocArtifact) GetArtifactTypeOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.ArtifactType, true +} + +// SetArtifactType sets field value +func (o *DocArtifact) SetArtifactType(v string) { + o.ArtifactType = v +} + +func (o DocArtifact) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o DocArtifact) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.CustomProperties) { + toSerialize["customProperties"] = o.CustomProperties + } + if !IsNil(o.Description) { + toSerialize["description"] = o.Description + } + if !IsNil(o.ExternalID) { + toSerialize["externalID"] = o.ExternalID + } + if !IsNil(o.Uri) { + toSerialize["uri"] = o.Uri + } + if !IsNil(o.State) { + toSerialize["state"] = o.State + } + if !IsNil(o.Name) { + toSerialize["name"] = o.Name + } + if !IsNil(o.Id) { + toSerialize["id"] = o.Id + } + if !IsNil(o.CreateTimeSinceEpoch) { + toSerialize["createTimeSinceEpoch"] = o.CreateTimeSinceEpoch + } + if !IsNil(o.LastUpdateTimeSinceEpoch) { + toSerialize["lastUpdateTimeSinceEpoch"] = o.LastUpdateTimeSinceEpoch + } + toSerialize["artifactType"] = o.ArtifactType + return toSerialize, nil +} + +type NullableDocArtifact struct { + value *DocArtifact + isSet bool +} + +func (v NullableDocArtifact) Get() *DocArtifact { + return v.value +} + +func (v *NullableDocArtifact) Set(val *DocArtifact) { + v.value = val + v.isSet = true +} + +func (v NullableDocArtifact) IsSet() bool { + return v.isSet +} + +func (v *NullableDocArtifact) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableDocArtifact(val *DocArtifact) *NullableDocArtifact { + return &NullableDocArtifact{value: val, isSet: true} +} + +func (v NullableDocArtifact) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableDocArtifact) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +}