Loading go-apps/meep-app-enablement/server/capif-mgmt/api_mec_service_mgmt.go +4 −0 Original line number Diff line number Diff line Loading @@ -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) } Loading go-apps/meep-app-enablement/server/capif-mgmt/convert.go +9 −0 Original line number Diff line number Diff line Loading @@ -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) Loading go-apps/meep-app-enablement/server/capif-mgmt/model_mec_service_info_capif_ext_patch.go 0 → 100644 +24 −0 Original line number Diff line number Diff line /* * 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"` } go-apps/meep-app-enablement/server/capif-mgmt/model_service_api_description_patch.go 0 → 100644 +14 −0 Original line number Diff line number Diff line /* * 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"` } go-apps/meep-app-enablement/server/capif-mgmt/service-mgmt.go +159 −0 Original line number Diff line number Diff line Loading @@ -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") Loading Loading
go-apps/meep-app-enablement/server/capif-mgmt/api_mec_service_mgmt.go +4 −0 Original line number Diff line number Diff line Loading @@ -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) } Loading
go-apps/meep-app-enablement/server/capif-mgmt/convert.go +9 −0 Original line number Diff line number Diff line Loading @@ -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) Loading
go-apps/meep-app-enablement/server/capif-mgmt/model_mec_service_info_capif_ext_patch.go 0 → 100644 +24 −0 Original line number Diff line number Diff line /* * 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"` }
go-apps/meep-app-enablement/server/capif-mgmt/model_service_api_description_patch.go 0 → 100644 +14 −0 Original line number Diff line number Diff line /* * 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"` }
go-apps/meep-app-enablement/server/capif-mgmt/service-mgmt.go +159 −0 Original line number Diff line number Diff line Loading @@ -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") Loading