Skip to content

Commit

Permalink
fix: potential problems that may cause panic (#160)
Browse files Browse the repository at this point in the history
* fix potential problems that may cause panic

Signed-off-by: gatici <[email protected]>

* Start logging with lowercase letters

Signed-off-by: gatici <[email protected]>

* chore: remove empty spaces

Signed-off-by: gatici <[email protected]>

* chore: Add blank lines between logical blocks

Signed-off-by: gatici <[email protected]>

* Handle all unhandled errors in nf_management.go

Signed-off-by: gatici <[email protected]>

* chore: create version 1.6.1

Signed-off-by: gatici <[email protected]>

* fix: start logs with lowercase letters

Signed-off-by: gatici <[email protected]>

* fix: remove empty spaces

Signed-off-by: gatici <[email protected]>

* fix: remove new line character

Signed-off-by: gatici <[email protected]>

---------

Signed-off-by: gatici <[email protected]>
  • Loading branch information
gatici authored Dec 11, 2024
1 parent f11ee74 commit a527d15
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 65 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.6.1-dev
1.6.1
10 changes: 5 additions & 5 deletions management/api_nf_instance_id_document.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
"github.com/omec-project/util/httpwrapper"
)

// DeregisterNFInstance - Deregisters a given NF Instance
// HTTPDeregisterNFInstance - Deregisters a given NF Instance
func HTTPDeregisterNFInstance(c *gin.Context) {
// parse nfInstanceId

Expand All @@ -47,7 +47,7 @@ func HTTPDeregisterNFInstance(c *gin.Context) {
}
}

// GetNFInstance - Read the profile of a given NF Instance
// HTTPGetNFInstance - Read the profile of a given NF Instance
func HTTPGetNFInstance(c *gin.Context) {
req := httpwrapper.NewRequest(c.Request, nil)
req.Params["nfInstanceID"] = c.Params.ByName("nfInstanceID")
Expand All @@ -68,7 +68,7 @@ func HTTPGetNFInstance(c *gin.Context) {
}
}

// RegisterNFInstance - Register a new NF Instance
// HTTPRegisterNFInstance - Register a new NF Instance
func HTTPRegisterNFInstance(c *gin.Context) {
var nfprofile models.NfProfile

Expand Down Expand Up @@ -124,7 +124,7 @@ func HTTPRegisterNFInstance(c *gin.Context) {
}
}

// UpdateNFInstance - Update NF Instance profile
// HTTPUpdateNFInstance Update NF Instance profile
func HTTPUpdateNFInstance(c *gin.Context) {
// step 1: retrieve http request body
requestBody, err := c.GetRawData()
Expand All @@ -151,7 +151,7 @@ func HTTPUpdateNFInstance(c *gin.Context) {
logger.ManagementLog.Warnln(err)
problemDetails := models.ProblemDetails{
Status: http.StatusInternalServerError,
Cause: "SYSTEM_FAILURE",
Cause: "SERIALIZATION_FAILURE",
Detail: err.Error(),
}
c.JSON(http.StatusInternalServerError, problemDetails)
Expand Down
186 changes: 127 additions & 59 deletions producer/nf_management.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,36 @@ func HandleNFRegisterRequest(request *httpwrapper.Request) *httpwrapper.Response
func HandleUpdateNFInstanceRequest(request *httpwrapper.Request) *httpwrapper.Response {
logger.ManagementLog.Infoln("Handle UpdateNFInstanceRequest")
nfInstanceID := request.Params["nfInstanceID"]
patchJSON := request.Body.([]byte)
if nfInstanceID == "" {
logger.ManagementLog.Errorln("nfInstanceID is missing")
return httpwrapper.NewResponse(http.StatusBadRequest, nil, map[string]string{"error": "Missing nfInstanceID"})
}

response := UpdateNFInstanceProcedure(nfInstanceID, patchJSON)
if response != nil {
stats.IncrementNrfRegistrationsStats("update", fmt.Sprint(response["nfType"]), "SUCCESS")
return httpwrapper.NewResponse(http.StatusOK, nil, response)
} else {
return httpwrapper.NewResponse(http.StatusNoContent, nil, nil)
patchJSON, ok := request.Body.([]byte)
if !ok {
logger.ManagementLog.Errorln("invalid body format")
return httpwrapper.NewResponse(http.StatusBadRequest, nil, map[string]string{"error": "Invalid body format"})
}

response, err := updateNFInstanceProcedure(nfInstanceID, patchJSON)
if err != nil {
logger.ManagementLog.Errorln("updateNFInstanceProcedure failed:", err)
return httpwrapper.NewResponse(http.StatusInternalServerError, nil, map[string]string{"error": "Update procedure failed"})
}

if response == nil {
logger.ManagementLog.Errorln("received nil response after update procedure")
return httpwrapper.NewResponse(http.StatusInternalServerError, nil, map[string]string{"error": "Update procedure returned nil response"})
}

nfType, ok := response["nfType"].(string)
if !ok {
logger.ManagementLog.Warnln("response missing 'nfType' or wrong format")
nfType = "unknown"
}

stats.IncrementNrfRegistrationsStats("update", nfType, "SUCCESS")
return httpwrapper.NewResponse(http.StatusOK, nil, response)
}

func HandleGetNFInstancesRequest(request *httpwrapper.Request) *httpwrapper.Response {
Expand Down Expand Up @@ -226,9 +247,14 @@ func UpdateSubscriptionProcedure(subscriptionID string, patchJSON []byte) (respo
func RemoveSubscriptionProcedure(subscriptionID string) {
collName := "Subscriptions"
filter := bson.M{"subscriptionId": subscriptionID}
logger.ManagementLog.Infoln("removing SubscriptionId:", subscriptionID)

logger.ManagementLog.Infoln("Removing SubscriptionId: ", subscriptionID)
dbadapter.DBClient.RestfulAPIDeleteMany(collName, filter)
err := dbadapter.DBClient.RestfulAPIDeleteMany(collName, filter)
if err != nil {
logger.ManagementLog.Errorf("failed to remove subscription with ID %s: %v", subscriptionID, err)
return
}
logger.ManagementLog.Infof("removed subscription with ID %s", subscriptionID)
}

func GetNFInstancesProcedure(nfType string, limit int) (response *nrf_context.UriList,
Expand Down Expand Up @@ -262,19 +288,49 @@ func NFDeleteAll(nfType string) (problemDetails *models.ProblemDetails) {
collName := "NfProfile"
filter := bson.M{"nfType": nfType}

dbadapter.DBClient.RestfulAPIDeleteMany(collName, filter)
err := dbadapter.DBClient.RestfulAPIDeleteMany(collName, filter)
if err != nil {
logger.ManagementLog.Errorln("failed to delete NF profiles of type %s: %v", nfType, err)
problemDetails = &models.ProblemDetails{
Title: "NF Profiles Deletion Failed",
Status: 500,
Detail: err.Error(),
}
return problemDetails
}

logger.ManagementLog.Infoln("successfully deleted NF profiles of type %s", nfType)
return nil
}

func NFDeregisterProcedure(nfInstanceID string) (nfType string, problemDetails *models.ProblemDetails) {
collName := "NfProfile"
filter := bson.M{"nfInstanceId": nfInstanceID}
nfType = GetNfTypeByNfInstanceID(nfInstanceID)
nfProfilesRaw, _ := dbadapter.DBClient.RestfulAPIGetMany(collName, filter)

nfProfilesRaw, err := dbadapter.DBClient.RestfulAPIGetMany(collName, filter)
if err != nil {
logger.ManagementLog.Warnln("error fetching NF profiles:", err)
problemDetails = &models.ProblemDetails{
Status: http.StatusInternalServerError,
Cause: "FETCH_ERROR",
Detail: err.Error(),
}
return "", problemDetails
}

time.Sleep(time.Duration(1) * time.Second)

dbadapter.DBClient.RestfulAPIDeleteMany(collName, filter)
deleteManyErr := dbadapter.DBClient.RestfulAPIDeleteMany(collName, filter)
if deleteManyErr != nil {
logger.ManagementLog.Warnln("error in deleting NF profiles:", deleteManyErr)
problemDetails = &models.ProblemDetails{
Status: http.StatusInternalServerError,
Cause: "NF_DELETE_ERROR",
Detail: deleteManyErr.Error(),
}
return "", problemDetails
}

// nfProfile data for response
nfProfiles, err := util.Decode(nfProfilesRaw, time.RFC3339)
Expand All @@ -288,28 +344,34 @@ func NFDeregisterProcedure(nfInstanceID string) (nfType string, problemDetails *
return "", problemDetails
}

/* NF Down Notification to other instances of same NfType */
// NF Down Notification to other instances of same NfType
if len(nfProfiles) != 0 {
sendNFDownNotification(nfProfiles[0], nfInstanceID)

uriList := nrf_context.GetNofificationUri(nfProfiles[0])

nfInstanceUri := nrf_context.GetNfInstanceURI(nfInstanceID)
// set info for NotificationData
Notification_event := models.NotificationEventType_DEREGISTERED

for _, uri := range uriList {
logger.ManagementLog.Infof("Status Notification Uri: %v", uri)
logger.ManagementLog.Infof("status Notification Uri: %v", uri)
problemDetails = SendNFStatusNotify(Notification_event, nfInstanceUri, uri)
if problemDetails != nil {
logger.ManagementLog.Infoln("Error in status notify ", problemDetails)
logger.ManagementLog.Infoln("error in status notify", problemDetails)
}
}
}

/* delete subscriptions of deregistered NF instance */
// delete subscriptions of deregistered NF instance
filter = bson.M{"subscrCond.nfInstanceId": nfInstanceID}
dbadapter.DBClient.RestfulAPIDeleteMany("Subscriptions", filter)
deleteErr := dbadapter.DBClient.RestfulAPIDeleteMany("Subscriptions", filter)
if deleteErr != nil {
logger.ManagementLog.Warnln("error in deleting subscriptions:", deleteErr)
problemDetails = &models.ProblemDetails{
Status: http.StatusInternalServerError,
Cause: "SUBSCRIPTION_DELETE_ERROR",
Detail: deleteErr.Error(),
}
return "", problemDetails
}

return nfType, nil
}
Expand All @@ -330,53 +392,59 @@ func sendNFDownNotification(nfProfile models.NfProfile, nfInstanceID string) {
}
}

func UpdateNFInstanceProcedure(nfInstanceID string, patchJSON []byte) (response map[string]interface{}) {
func updateNFInstanceProcedure(nfInstanceID string, patchJSON []byte) (response map[string]interface{}, err error) {
// Validation for NF Instance ID
if nfInstanceID == "" {
logger.ManagementLog.Errorln("nf Instance ID is required")
return nil, fmt.Errorf("NF Instance ID is required")
}
collName := "NfProfile"
filter := bson.M{"nfInstanceId": nfInstanceID}

err := dbadapter.DBClient.RestfulAPIJSONPatch(collName, filter, patchJSON)
if err == nil {
nf, _ := dbadapter.DBClient.RestfulAPIGetOne(collName, filter)

nfProfilesRaw := []map[string]interface{}{
nf,
}

nfProfiles, decodeErr := util.Decode(nfProfilesRaw, time.RFC3339)
if decodeErr != nil {
logger.ManagementLog.Info(decodeErr.Error())
}

// Update expiry time for document.
// Currently we are using 3 times the hearbeat timer as the expiry time interval.
// We should update it to be configurable : TBD
if factory.NrfConfig.Configuration.NfProfileExpiryEnable {
timein := time.Now().Local().Add(time.Second * time.Duration(factory.NrfConfig.Configuration.NfKeepAliveTime*3))
nf["expireAt"] = timein
}
// dbadapter.DBClient.RestfulAPIJSONPatch(collName, filter, jsonStr)
if ok, _ := dbadapter.DBClient.RestfulAPIPutOne(collName, filter, nf); ok {
logger.ManagementLog.Infof("nf profile [%s] update success", nfProfiles[0].NfType)
} else {
logger.ManagementLog.Infof("nf profile [%s] update failed", nfProfiles[0].NfType)
}
// Patch the existing NF Instance
patchError := dbadapter.DBClient.RestfulAPIJSONPatch(collName, filter, patchJSON)
if patchError != nil {
logger.ManagementLog.Errorln("patch error in UpdateNFInstanceProcedure:", patchError)
return nil, fmt.Errorf("patch error: %v", patchError)
}
// Get the updated NF Instance
nf, getErr := dbadapter.DBClient.RestfulAPIGetOne(collName, filter)
if getErr != nil || nf == nil {
logger.ManagementLog.Errorln("failed to get NF instance:", getErr)
return nil, fmt.Errorf("failed to get NF instance: %v", getErr)
}

// set info for NotificationData
// Notification not required so commenting it
/* Notification_event := models.NotificationEventType_PROFILE_CHANGED
uriList := nrf_context.GetNofificationUri(nfProfiles[0])
nfProfilesRaw := []map[string]interface{}{nf}

nfInstanceUri := nrf_context.GetNfInstanceURI(nfInstanceID)
// Decode NF instance
nfProfiles, decodeErr := util.Decode(nfProfilesRaw, time.RFC3339)
if decodeErr != nil {
logger.ManagementLog.Errorln("decoding error:", decodeErr)
return nil, fmt.Errorf("decoding error: %v", decodeErr)
}

for _, uri := range uriList {
SendNFStatusNotify(Notification_event, nfInstanceUri, uri)
}*/
if len(nfProfiles) == 0 {
// Handle empty decoded profiles case
logger.ManagementLog.Errorln("decoded NF profiles are empty")
return nil, fmt.Errorf("decoded NF profiles are empty")
}

return nf
} else {
logger.ManagementLog.Errorln("Marshal error in UpdateNFInstanceProcedure: ", err)
return nil
// Update expiry time if enabled
// Currently we are using 3 times the hearbeat timer as the expiry time interval.
// We should update it to be configurable : TBD
if factory.NrfConfig.Configuration.NfProfileExpiryEnable {
timein := time.Now().Local().Add(time.Second * time.Duration(factory.NrfConfig.Configuration.NfKeepAliveTime*3))
nf["expireAt"] = timein
}
// Put the updated NF instance
_, putErr := dbadapter.DBClient.RestfulAPIPutOne(collName, filter, nf)
if putErr != nil {
logger.ManagementLog.Errorf("nf profile [%s] update failed: %v", nfProfiles[0].NfType, putErr)
return nil, fmt.Errorf("NF profile update is failed: %v", putErr)
}

logger.ManagementLog.Infof("nf profile [%s] update success", nfProfiles[0].NfType)
return nf, nil
}

func GetNFInstanceProcedure(nfInstanceID string) (response map[string]interface{}) {
Expand Down

0 comments on commit a527d15

Please sign in to comment.