package apis
import (
+ "fmt"
"io"
"net/http"
"os"
- "fmt"
"gerrit.o-ran-sc.org/r/aiml-fw/awmf/modelmgmtservice/core"
"gerrit.o-ran-sc.org/r/aiml-fw/awmf/modelmgmtservice/db"
"gerrit.o-ran-sc.org/r/aiml-fw/awmf/modelmgmtservice/logging"
"gerrit.o-ran-sc.org/r/aiml-fw/awmf/modelmgmtservice/models"
"github.com/gin-gonic/gin"
+ "github.com/go-playground/validator/v10"
"github.com/google/uuid"
-
)
type MmeApiHandler struct {
func (m *MmeApiHandler) RegisterModel(cont *gin.Context) {
- var modelInfo models.ModelInfo
+ var modelInfo models.ModelRelatedInformation
if err := cont.ShouldBindJSON(&modelInfo); err != nil {
cont.JSON(http.StatusBadRequest, gin.H{
id := uuid.New()
modelInfo.Id = id.String()
- // TODO: validate the object
+ validate := validator.New()
+ if err := validate.Struct(modelInfo); err != nil {
+ cont.JSON(http.StatusBadRequest, gin.H{
+ "error": err.Error(),
+ })
+ return
+ }
if err := m.iDB.Create(modelInfo); err != nil {
logging.ERROR("error", err)
+ cont.JSON(http.StatusBadRequest, gin.H{
+ "Error": err.Error(),
+ })
return
}
logging.INFO("model is saved.")
-
+ cont.Header("Location", "/model-registrations/"+id.String())
cont.JSON(http.StatusCreated, gin.H{
"modelInfo": modelInfo,
})
queryParams := cont.Request.URL.Query()
//to check only modelName and modelVersion can be passed.
allowedParams := map[string]bool{
- "modelName": true,
+ "modelName": true,
"modelVersion": true,
}
}
}
- modelName:= cont.Query("modelName")
- modelVersion:= cont.Query("modelVersion")
+ modelName := cont.Query("modelName")
+ modelVersion := cont.Query("modelVersion")
if modelName == "" {
- //return all modelinfo stored
+ //return all modelinfo stored
models, err := m.iDB.GetAll()
if err != nil {
} else {
if modelVersion == "" {
// get all modelInfo by model name
- modelInfos, err:= m.iDB.GetModelInfoByName(modelName)
+ modelInfos, err := m.iDB.GetModelInfoByName(modelName)
if err != nil {
statusCode := http.StatusInternalServerError
logging.ERROR("Error occurred, send status code: ", statusCode)
}
cont.JSON(http.StatusOK, gin.H{
- "modelinfoList":modelInfos,
+ "modelinfoList": modelInfos,
})
return
- } else
- {
+ } else {
// get all modelInfo by model name and version
- modelInfo, err:= m.iDB.GetModelInfoByNameAndVer(modelName, modelVersion)
+ modelInfo, err := m.iDB.GetModelInfoByNameAndVer(modelName, modelVersion)
if err != nil {
statusCode := http.StatusInternalServerError
logging.ERROR("Error occurred, send status code: ", statusCode)
})
return
}
- if modelInfo.Id == ""{
+ if modelInfo.ModelId.ModelName != modelName && modelInfo.ModelId.ModelVersion != modelVersion {
statusCode := http.StatusNotFound
errMessage := fmt.Sprintf("Record not found with modelName: %s and modelVersion: %s", modelName, modelVersion)
logging.ERROR("Record not found, send status code: ", statusCode)
}
cont.JSON(http.StatusOK, gin.H{
- "modelinfo":modelInfo,
+ "modelinfo": modelInfo,
})
return
}
func (m *MmeApiHandler) GetModelInfoById(cont *gin.Context) {
logging.INFO("Get model info by id ...")
- id := cont.Param("id")
+ id := cont.Param("modelRegistrationId")
modelInfo, err := m.iDB.GetModelInfoById(id)
if err != nil {
logging.ERROR("error:", err)
})
return
}
- if modelInfo.Id == ""{
+ if modelInfo.Id == "" {
statusCode := http.StatusNotFound
errMessage := fmt.Sprintf("Record not found with id: %s", id)
logging.ERROR("Record not found, send status code: ", statusCode)
func (m *MmeApiHandler) UpdateModel(c *gin.Context) {
logging.INFO("Updating model...")
- id := c.Param("id")
- var modelInfo models.ModelInfo
+ id := c.Param("modelRegistrationId")
+ var modelInfo models.ModelRelatedInformation
if err := c.ShouldBindJSON(&modelInfo); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
logging.INFO("model updated")
c.JSON(http.StatusOK, gin.H{
- "modelinfo":modelInfo,
+ "modelinfo": modelInfo,
})
}
-func (m *MmeApiHandler) DeleteModel(c *gin.Context) {
- logging.INFO("Deleting model...")
- id := c.Param("id")
- if err := m.iDB.Delete(id); err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{
+func (m *MmeApiHandler) DeleteModel(cont *gin.Context) {
+ id := cont.Param("modelRegistrationId")
+ logging.INFO("Deleting model... id = ", id)
+ rowsAffected, err := m.iDB.Delete(id)
+ if err != nil {
+ cont.JSON(http.StatusInternalServerError, gin.H{
"error": err.Error(),
})
return
}
- c.JSON(http.StatusOK, gin.H{"message": "modelInfo deleted"})
+ message := "modelInfo deleted"
+ if rowsAffected == 0 {
+ message = fmt.Sprintf("id = %s already doesn't exist in database", id)
+ }
+ cont.JSON(http.StatusOK, gin.H{"message": message})
}
)
var registerModelBody = `{
- "id" : "id",
- "modelId": {
- "modelName": "test-model",
- "modelVersion":"1"
- },
- "description": "testing",
- "metaInfo": {
- "metadata": {
- "author":"tester"
- }
- }
+ "id" : "id",
+ "modelId": {
+ "modelName": "model3",
+ "modelVersion" : "2"
+ },
+ "description": "hello world2",
+ "modelInformation": {
+ "metadata": {
+ "author": "someone"
+ },
+ "inputDataType": "pdcpBytesDl,pdcpBytesUl,kpi",
+ "outputDataType": "c, d"
+ }
}`
type dbMgrMock struct {
db.IDB
}
-func (i *iDBMock) Create(modelInfo models.ModelInfo) error {
+func (i *iDBMock) Create(modelInfo models.ModelRelatedInformation) error {
args := i.Called(modelInfo)
return args.Error(0)
}
-func (i *iDBMock) GetByID(id string) (*models.ModelInfo, error) {
+func (i *iDBMock) GetByID(id string) (*models.ModelRelatedInformation, error) {
return nil, nil
}
-func (i *iDBMock) GetAll() ([]models.ModelInfo, error) {
+func (i *iDBMock) GetAll() ([]models.ModelRelatedInformation, error) {
args := i.Called()
if _, ok := args.Get(1).(error); !ok {
- return args.Get(0).([]models.ModelInfo), nil
+ return args.Get(0).([]models.ModelRelatedInformation), nil
} else {
- var emptyModelInfo []models.ModelInfo
+ var emptyModelInfo []models.ModelRelatedInformation
return emptyModelInfo, args.Error(1)
}
}
-func (i *iDBMock) Update(modelInfo models.ModelInfo) error {
+func (i *iDBMock) Update(modelInfo models.ModelRelatedInformation) error {
return nil
}
-func (i *iDBMock) Delete(id string) error {
- return nil
+func (i *iDBMock) Delete(id string) (int64, error) {
+ return 1, nil
}
func TestRegisterModel(t *testing.T) {
handler := apis.NewMmeApiHandler(nil, iDBMockInst)
router := routers.InitRouter(handler)
w := httptest.NewRecorder()
- req, _ := http.NewRequest("POST", "/registerModel", strings.NewReader(registerModelBody))
+ req, _ := http.NewRequest("POST", "/model-registrations", strings.NewReader(registerModelBody))
router.ServeHTTP(w, req)
assert.Equal(t, 201, w.Code)
}
// Setting Mock
iDBmockInst := new(iDBMock)
- iDBmockInst.On("GetAll").Return([]models.ModelInfo{
+ iDBmockInst.On("GetAll").Return([]models.ModelRelatedInformation{
{
Id: "1234",
ModelId: models.ModelID{
ModelVersion: "v1.0",
},
Description: "this is test modelINfo",
- ModelSpec: models.ModelSpec{
+ ModelInformation: models.ModelInformation{
Metadata: models.Metadata{
- Author: "testing",
+ Author: "someone",
},
+ InputDataType: "pdcpBytesDl,pdcpBytesUl,kpi",
+ OutputDataType: "c,d",
},
},
}, nil)
response := responseRecorder.Result()
body, _ := io.ReadAll(response.Body)
- var modelInfos []models.ModelInfo
+ var modelInfos []models.ModelRelatedInformation
logging.INFO(modelInfos)
json.Unmarshal(body, &modelInfos)
// Setting Mock
iDBmockInst2 := new(iDBMock)
- iDBmockInst2.On("GetAll").Return([]models.ModelInfo{}, fmt.Errorf("db not available"))
+ iDBmockInst2.On("GetAll").Return([]models.ModelRelatedInformation{}, fmt.Errorf("db not available"))
handler := apis.NewMmeApiHandler(nil, iDBmockInst2)
router := routers.InitRouter(handler)
response := responseRecorder.Result()
body, _ := io.ReadAll(response.Body)
- var modelInfoListResp []models.ModelInfo
+ var modelInfoListResp []models.ModelRelatedInformation
json.Unmarshal(body, &modelInfoListResp)
assert.Equal(t, 500, responseRecorder.Code)
)
type IDB interface {
- Create(modelInfo models.ModelInfo) error
- GetByID(id string) (*models.ModelInfo, error)
- GetAll() ([]models.ModelInfo, error)
- GetModelInfoByName(modelName string)([]models.ModelInfo, error)
- GetModelInfoByNameAndVer(modelName string, modelVersion string)(*models.ModelInfo, error)
- GetModelInfoById(id string)(*models.ModelInfo, error)
- Update(modelInfo models.ModelInfo) error
- Delete(id string) error
+ Create(modelInfo models.ModelRelatedInformation) error
+ GetByID(id string) (*models.ModelRelatedInformation, error)
+ GetAll() ([]models.ModelRelatedInformation, error)
+ GetModelInfoByName(modelName string) ([]models.ModelRelatedInformation, error)
+ GetModelInfoByNameAndVer(modelName string, modelVersion string) (*models.ModelRelatedInformation, error)
+ GetModelInfoById(id string) (*models.ModelRelatedInformation, error)
+ Update(modelInfo models.ModelRelatedInformation) error
+ Delete(id string) (int64, error)
}
}
}
-func (repo *ModelInfoRepository) Create(modelInfo models.ModelInfo) error {
- repo.db.Create(modelInfo)
- return nil
+func (repo *ModelInfoRepository) Create(modelInfo models.ModelRelatedInformation) error {
+ result := repo.db.Create(modelInfo)
+ return result.Error
}
-func (repo *ModelInfoRepository) GetByID(id string) (*models.ModelInfo, error) {
+func (repo *ModelInfoRepository) GetByID(id string) (*models.ModelRelatedInformation, error) {
return nil, nil
}
-func (repo *ModelInfoRepository) GetAll() ([]models.ModelInfo, error) {
- var modelInfos []models.ModelInfo
+func (repo *ModelInfoRepository) GetAll() ([]models.ModelRelatedInformation, error) {
+ var modelInfos []models.ModelRelatedInformation
result := repo.db.Find(&modelInfos)
if result.Error != nil {
return nil, result.Error
return modelInfos, nil
}
-func (repo *ModelInfoRepository) Update(modelInfo models.ModelInfo) error {
+func (repo *ModelInfoRepository) Update(modelInfo models.ModelRelatedInformation) error {
if err := repo.db.Save(modelInfo).Error; err != nil {
return err
}
return nil
}
-func (repo *ModelInfoRepository) Delete(id string) error {
- logging.INFO("id is:", id)
- if err := repo.db.Delete(&models.ModelInfo{}, "id=?", id).Error; err != nil {
- return err
- }
- return nil
+func (repo *ModelInfoRepository) Delete(id string) (int64, error) {
+ result := repo.db.Delete(&models.ModelRelatedInformation{}, "id = ?", id)
+ return result.RowsAffected, result.Error
}
-func (repo *ModelInfoRepository) GetModelInfoByName(modelName string)([]models.ModelInfo, error){
- var modelInfos []models.ModelInfo
+func (repo *ModelInfoRepository) GetModelInfoByName(modelName string) ([]models.ModelRelatedInformation, error) {
+ var modelInfos []models.ModelRelatedInformation
result := repo.db.Where("model_name = ?", modelName).Find(&modelInfos)
if result.Error != nil {
return nil, result.Error
return modelInfos, nil
}
-func (repo *ModelInfoRepository) GetModelInfoByNameAndVer(modelName string, modelVersion string)(*models.ModelInfo, error){
- var modelInfo models.ModelInfo
+func (repo *ModelInfoRepository) GetModelInfoByNameAndVer(modelName string, modelVersion string) (*models.ModelRelatedInformation, error) {
+ var modelInfo models.ModelRelatedInformation
result := repo.db.Where("model_name = ? AND model_version = ?", modelName, modelVersion).Find(&modelInfo)
if result.Error != nil {
return nil, result.Error
}
return &modelInfo, nil
}
-func (repo *ModelInfoRepository) GetModelInfoById(id string)(*models.ModelInfo, error){
+
+func (repo *ModelInfoRepository) GetModelInfoById(id string) (*models.ModelRelatedInformation, error) {
logging.INFO("id is:", id)
- var modelInfo models.ModelInfo
+ var modelInfo models.ModelRelatedInformation
result := repo.db.Where("id = ?", id).Find(&modelInfo)
if result.Error != nil {
return nil, result.Error
}
return &modelInfo, nil
-}
\ No newline at end of file
+}
}
// Auto migrate the scheme
- db.AutoMigrate(&models.ModelInfo{})
+ db.AutoMigrate(&models.ModelRelatedInformation{})
repo := modelDB.NewModelInfoRepository(db)
router := routers.InitRouter(
package models
type Metadata struct {
- Author string `json:"author"`
+ Author string `json:"author" validate:"required"`
+ Owner string `json:"owner"`
}
-type ModelSpec struct {
- Metadata Metadata `json:"metadata" gorm:"embedded"`
+type TargetEnironment struct {
+ PlatformName string `json:"platformName" validate:"required"`
+ EnvironmentType string `json:"environmentType" validate:"required"`
+ DependencyList string `json:"dependencyList" validate:"required"`
+}
+
+type ModelInformation struct {
+ Metadata Metadata `json:"metadata" gorm:"embedded" validate:"required"`
+ InputDataType string `json:"inputDataType" validate:"required"` // this field will be a Comma Separated List
+ OutputDataType string `json:"outputDataType" validate:"required"` // this field will be a Comma Separated List
+ // TODO: gorm doesn't support list, need to find the right way
+ // TargetEnvironment []TargetEnironment `json:"targetEnvironment" gorm:"embedded"`
}
type ModelID struct {
- ModelName string `json:"modelName"`
- ModelVersion string `json:"modelVersion"`
+ ModelName string `json:"modelName" validate:"required" gorm:"primaryKey"`
+ ModelVersion string `json:"modelVersion" validate:"required" gorm:"primaryKey"`
+ ArtifactVersion string `json:"artifactVersion"`
}
-type ModelInfo struct {
- Id string `json:"id" gorm:"primaryKey"`
- ModelId ModelID `json:"model-id,omitempty" gorm:"embedded"`
- Description string `json:"description"`
- ModelSpec ModelSpec `json:"meta-info" gorm:"embedded"`
+type ModelRelatedInformation struct {
+ Id string `json:"id" gorm:"unique"`
+ ModelId ModelID `json:"modelId,omitempty" validate:"required" gorm:"embedded;primaryKey"`
+ Description string `json:"description" validate:"required"`
+ ModelInformation ModelInformation `json:"modelInformation" validate:"required" gorm:"embedded"`
+ ModelLocation string `json:"modelLocation"`
}
type ModelInfoResponse struct {
r := gin.New()
r.Use(gin.Logger())
r.Use(gin.Recovery())
+ // As per R1-AP v6
+ r.POST("/model-registrations", handler.RegisterModel)
+ r.GET("/model-registrations/:modelRegistrationId", handler.GetModelInfoById)
+ r.PUT("/model-registrations/:modelRegistrationId", handler.UpdateModel)
+ r.DELETE("/model-registrations/:modelRegistrationId", handler.DeleteModel)
- r.POST("/registerModel", handler.RegisterModel)
r.GET("/getModelInfo", handler.GetModelInfo)
- r.PUT("/modelInfo/:id", handler.UpdateModel)
- r.GET("/modelInfo/:id", handler.GetModelInfoById)
- r.DELETE("/modelInfo/:id", handler.DeleteModel)
r.GET("/getModelInfo/:modelName", handler.GetModelInfoByName)
r.POST("/uploadModel/:modelName", handler.UploadModel)
r.GET("/downloadModel/:modelName/model.zip", handler.DownloadModel)