diff --git a/go-apps/meep-app-enablement/server/capif-mgmt/api_mec_service_mgmt.go b/go-apps/meep-app-enablement/server/capif-mgmt/api_mec_service_mgmt.go index e230ebd1a992ecb09b5c90fab373b383da0cd0ea..8f1fca70e6da72ed5b98d7fc4e0de04457ef69ec 100644 --- a/go-apps/meep-app-enablement/server/capif-mgmt/api_mec_service_mgmt.go +++ b/go-apps/meep-app-enablement/server/capif-mgmt/api_mec_service_mgmt.go @@ -47,6 +47,10 @@ func AppServicesServiceIdPUT(w http.ResponseWriter, r *http.Request) { appServicesByIdPUT(w, r) } +func AppServicesServiceIdPATCH(w http.ResponseWriter, r *http.Request) { + appServicesByIdPATCH(w, r) +} + func ApplicationsSubscriptionDELETE(w http.ResponseWriter, r *http.Request) { applicationsSubscriptionDELETE(w, r) } diff --git a/go-apps/meep-app-enablement/server/capif-mgmt/convert.go b/go-apps/meep-app-enablement/server/capif-mgmt/convert.go index 381f22c26f59420ec82755d2cf1920531b1a0b52..552e31521e9376ce8cd4b3072401a43e3bc86e3f 100644 --- a/go-apps/meep-app-enablement/server/capif-mgmt/convert.go +++ b/go-apps/meep-app-enablement/server/capif-mgmt/convert.go @@ -40,6 +40,15 @@ func convertServiceInfoToJson_1(obj *ServiceApiDescription) string { return string(jsonInfo) } +func convertServiceInfoToJson_2(obj *ServiceApiDescriptionPatch) string { + jsonInfo, err := json.Marshal(*obj) + if err != nil { + log.Error(err.Error()) + return "" + } + return string(jsonInfo) +} + func convertJsonToServiceInfo(jsonInfo string) *ServiceInfo { var obj ServiceInfo err := json.Unmarshal([]byte(jsonInfo), &obj) diff --git a/go-apps/meep-app-enablement/server/capif-mgmt/model_mec_service_info_capif_ext_patch.go b/go-apps/meep-app-enablement/server/capif-mgmt/model_mec_service_info_capif_ext_patch.go new file mode 100644 index 0000000000000000000000000000000000000000..23aa2fd07bcec66115526a38bad4e4b6a41b1995 --- /dev/null +++ b/go-apps/meep-app-enablement/server/capif-mgmt/model_mec_service_info_capif_ext_patch.go @@ -0,0 +1,24 @@ +/* + * MEC service management realized by CAPIF APIs + * + * The ETSI MEC ISG MEC011 MEC Service Management realized by CAPIF APIs described using OpenAPI + * + * API version: 3.2.1 + * Contact: cti_support@etsi.org + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package server + +type MecServiceInfoCapifExtPatch struct { + Serializer *SerializerType `json:"serializer,omitempty"` + + State *ServiceState `json:"state,omitempty"` + + ScopeOfLocality *LocalityType `json:"scopeOfLocality,omitempty"` + + ConsumedLocalOnly bool `json:"consumedLocalOnly,omitempty"` + + IsLocal bool `json:"isLocal,omitempty"` + + Category *CategoryRef `json:"category,omitempty"` +} diff --git a/go-apps/meep-app-enablement/server/capif-mgmt/model_service_api_description_patch.go b/go-apps/meep-app-enablement/server/capif-mgmt/model_service_api_description_patch.go new file mode 100644 index 0000000000000000000000000000000000000000..cf0cf27f0cac981c0e641ec6b3d3803c4591c65b --- /dev/null +++ b/go-apps/meep-app-enablement/server/capif-mgmt/model_service_api_description_patch.go @@ -0,0 +1,14 @@ +/* + * MEC service management realized by CAPIF APIs + * + * The ETSI MEC ISG MEC011 MEC Service Management realized by CAPIF APIs described using OpenAPI + * + * API version: 3.2.1 + * Contact: cti_support@etsi.org + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package server + +type ServiceApiDescriptionPatch struct { + VendorSpecificUrnetsimeccapifextserviceInfo *MecServiceInfoCapifExtPatch `json:"vendorSpecific-urn:etsi:mec:capifext:service-info,omitempty"` +} diff --git a/go-apps/meep-app-enablement/server/capif-mgmt/service-mgmt.go b/go-apps/meep-app-enablement/server/capif-mgmt/service-mgmt.go index 38da15f41b385e2667e5d0fd7f3718e912481199..81728febff01e3c6032bd50edffc716d996c36d1 100644 --- a/go-apps/meep-app-enablement/server/capif-mgmt/service-mgmt.go +++ b/go-apps/meep-app-enablement/server/capif-mgmt/service-mgmt.go @@ -570,6 +570,165 @@ func appServicesByIdPUT(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, convertServiceInfoToJson_1(dsInfo)) } +func appServicesByIdPATCH(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + log.Info("appServicesByIdPUT") + vars := mux.Vars(r) + svcId := vars["serviceApiId"] + appId := vars["apfId"] + + mutex.Lock() + defer mutex.Unlock() + + // Get App instance + appInfo, err := getAppInfo(appId) + if err != nil { + errHandlerProblemDetails(w, err.Error(), http.StatusNotFound) + return + } + + // Validate App info + code, problemDetails, err := validateAppInfo(appInfo) + if err != nil { + log.Error(err.Error()) + if problemDetails != "" { + w.WriteHeader(code) + fmt.Fprint(w, problemDetails) + } else { + errHandlerProblemDetails(w, err.Error(), code) + } + return + } + + // Get previous service info + sInfoPrevJson, err := getServiceById(appId, svcId) + if err != nil { + log.Error(err.Error()) + w.WriteHeader(http.StatusNotFound) + return + } + sInfoPrev := convertJsonToServiceInfo(sInfoPrevJson) + + // Retrieve request parameters from body + if r.Body == nil { + err := errors.New("Request body is missing") + errHandlerProblemDetails(w, err.Error(), http.StatusBadRequest) + return + } + // NOTE: Set default values for omitted fields + locality := MEC_HOST_LocalityType + sInfo := ServiceApiDescriptionPatch{ + VendorSpecificUrnetsimeccapifextserviceInfo: &MecServiceInfoCapifExtPatch{ + ScopeOfLocality: &locality, + IsLocal: true, + ConsumedLocalOnly: true, + }, + } + decoder := json.NewDecoder(r.Body) + err = decoder.Decode(&sInfo) + if err != nil { + log.Error(err.Error()) + errHandlerProblemDetails(w, err.Error(), http.StatusInternalServerError) + return + } + + // aefProfile := &AefProfile{ + // AefId: sInfo.AefProfiles[0].AefId, + // Versions: sInfo.AefProfiles[0].Versions, + // InterfaceDescriptions: sInfo.AefProfiles[0].InterfaceDescriptions, + // VendorSpecificUrnetsimeccapifexttransportInfo: &MecTransportInfoCapifExt{ + // Name: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Name, + // Type_: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Type_, + // Protocol: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Protocol, + // Version: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Version, + // Security: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Security, + // }, + // } + dsInfo := &ServiceApiDescriptionPatch{ + // ApiName: sInfo.ApiName, + // ApiId: sInfo.ApiId, + // AefProfiles: []AefProfile{*aefProfile}, + VendorSpecificUrnetsimeccapifextserviceInfo: &MecServiceInfoCapifExtPatch{ + Serializer: sInfo.VendorSpecificUrnetsimeccapifextserviceInfo.Serializer, + State: sInfo.VendorSpecificUrnetsimeccapifextserviceInfo.State, + ScopeOfLocality: sInfo.VendorSpecificUrnetsimeccapifextserviceInfo.ScopeOfLocality, + ConsumedLocalOnly: sInfo.VendorSpecificUrnetsimeccapifextserviceInfo.ConsumedLocalOnly, + IsLocal: sInfo.VendorSpecificUrnetsimeccapifextserviceInfo.IsLocal, + Category: sInfo.VendorSpecificUrnetsimeccapifextserviceInfo.Category, + }, + } + + // transportInfo_ := TransportInfo{ + // Id: sInfo.AefProfiles[0].AefId, + // Name: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Name, + // Type_: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Type_, + // Protocol: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Protocol, + // Version: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Version, + // Endpoint: sInfo.AefProfiles[0].InterfaceDescriptions, + // Security: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Security, + // } + + // Create Service + _sInfo := ServiceInfo{ + SerCategory: dsInfo.VendorSpecificUrnetsimeccapifextserviceInfo.Category, + State: dsInfo.VendorSpecificUrnetsimeccapifextserviceInfo.State, + Serializer: dsInfo.VendorSpecificUrnetsimeccapifextserviceInfo.Serializer, + ScopeOfLocality: dsInfo.VendorSpecificUrnetsimeccapifextserviceInfo.ScopeOfLocality, + ConsumedLocalOnly: dsInfo.VendorSpecificUrnetsimeccapifextserviceInfo.ConsumedLocalOnly, + IsLocal: dsInfo.VendorSpecificUrnetsimeccapifextserviceInfo.IsLocal, + LivenessInterval: 0, + } + + // Current implementation only supports state parameter change; + // Make sure none of the other service information fields have changed + state := *_sInfo.State + *_sInfo.State = *sInfoPrev.State + // isLocal is only set in responses, subscriptions and notifications; + // Ignore this field while comparing the previous & new service info structs + _sInfo.IsLocal = sInfoPrev.IsLocal + + // Compare service information as JSON strings + /* FSCOM: It is not specified that only the ServiceInfo state property may be changed in ETSI GS MEC 011 V3.2.1 (2024-04) + sInfoJson := convertServiceInfoToJson(&sInfo) + if sInfoJson != sInfoPrevJson { + errStr := "Only the ServiceInfo state property may be changed" + log.Error(errStr) + errHandlerProblemDetails(w, errStr, http.StatusBadRequest) + return + }*/ + + // Compare service info states & update DB if necessary + *_sInfo.State = state + if *_sInfo.State != *sInfoPrev.State { + err, retCode := setService(appId, &_sInfo, STATE_CHANGED_ServiceAvailabilityNotificationChangeType) + if err != nil { + log.Error(err.Error()) + errHandlerProblemDetails(w, err.Error(), retCode) + return + } + } + + // Compare LivenessInterval + if _sInfo.LivenessInterval != sInfoPrev.LivenessInterval { + if _, ok := livenessTimerList[_sInfo.SerInstanceId]; ok { // An entry already exist + if _sInfo.LivenessInterval != 0 { // update it + updateLivenessTicker(_sInfo) + } else { + deleteLivenessTicker(_sInfo.SerInstanceId) + } + } else { // No entry + if _sInfo.LivenessInterval != 0 { // Create a new entry + createLivenessTicker(_sInfo) + } + } + } // else, nothing to do + _sInfo.LivenessInterval = sInfoPrev.LivenessInterval + + // Send response + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, convertServiceInfoToJson_2(dsInfo)) +} + func appServicesByIdDELETE(w http.ResponseWriter, r *http.Request) { log.Info("appServicesByIdDELETE") w.Header().Set("Content-Type", "application/json; charset=UTF-8") diff --git a/go-apps/meep-app-enablement/server/routers.go b/go-apps/meep-app-enablement/server/routers.go index 1f878a8deb411b57dc98bba632afda9fcd9bac8a..ce05174fae9c5991f2b5317b73807b156ac3c1e5 100644 --- a/go-apps/meep-app-enablement/server/routers.go +++ b/go-apps/meep-app-enablement/server/routers.go @@ -371,6 +371,13 @@ var routes = Routes{ capifMgmt.AppServicesServiceIdPUT, }, + Route{ + "AppServicesServiceIdPATCH", + strings.ToUpper("Patch"), + "/published-apis/v1/{apfId}/service-apis/{serviceApiId}", + capifMgmt.AppServicesServiceIdPATCH, + }, + Route{ "AppServicesServiceIdDELETE", strings.ToUpper("Delete"),