From e36af39645eb36385c32d4763b7ec6a198fd069e Mon Sep 17 00:00:00 2001 From: Patricia Reinoso Date: Fri, 19 Jul 2024 08:57:11 +0000 Subject: [PATCH] use DB instead of files Signed-off-by: Patricia Reinoso --- configapi/api_inventory_mgmt.go | 208 +++++++++++++++++++++++++++++++ configapi/routers.go | 36 ++++++ configmodels/config_msg.go | 5 + configmodels/model_inventory.go | 16 +++ proto/server/configEvtHandler.go | 67 +++++++++- 5 files changed, 330 insertions(+), 2 deletions(-) create mode 100644 configapi/api_inventory_mgmt.go create mode 100644 configmodels/model_inventory.go diff --git a/configapi/api_inventory_mgmt.go b/configapi/api_inventory_mgmt.go new file mode 100644 index 00000000..98ce230c --- /dev/null +++ b/configapi/api_inventory_mgmt.go @@ -0,0 +1,208 @@ +// SPDX-FileCopyrightText: 2021 Open Networking Foundation +// +// SPDX-License-Identifier: Apache-2.0 +// + +package configapi + +import ( + "encoding/json" + "strings" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/omec-project/util/httpwrapper" + "github.com/omec-project/webconsole/backend/logger" + "github.com/omec-project/webconsole/configmodels" + "github.com/omec-project/webconsole/dbadapter" + "go.mongodb.org/mongo-driver/bson" +) + +const ( + gnbDataColl = "webconsoleData.snapshots.gnbData" + upfDataColl = "webconsoleData.snapshots.upfData" +) + +//var configChannel chan *configmodels.ConfigMessage + +//var configLog *logrus.Entry + +func GetGnbs(c *gin.Context) { + setCorsHeader(c) + logger.WebUILog.Infoln("Get all gNBs") + + rawGnbs, errGetMany := dbadapter.CommonDBClient.RestfulAPIGetMany(gnbDataColl, bson.M{}) + if errGetMany != nil { + logger.DbLog.Warnln(errGetMany) + } + + var gnbs []*configmodels.Gnb + for _, rawGnb := range rawGnbs { + var gnbData configmodels.Gnb + err := json.Unmarshal(mapToByte(rawGnb), &gnbData) + if err != nil { + logger.DbLog.Errorf("Could not unmarshall gNB %v", rawGnb) + } + gnbs = append(gnbs, &gnbData) + } + c.JSON(http.StatusOK, gnbs) +} + +func GnbPostByName(c *gin.Context) { + logger.ConfigLog.Debugf("Received GnbPostByName ") + if ret := gnbPostHandler(c); ret == true { + c.JSON(http.StatusOK, gin.H{}) + } else { + c.JSON(http.StatusBadRequest, gin.H{}) + } +} + +func GnbDeleteByName(c *gin.Context) { + logger.ConfigLog.Debugf("Received GnbDeleteByName ") + if ret := gnbDeletetHandler(c); ret == true { + c.JSON(http.StatusOK, gin.H{}) + } else { + c.JSON(http.StatusBadRequest, gin.H{}) + } +} + +func gnbPostHandler(c *gin.Context) bool { + var gnbName string + var exists bool + if gnbName, exists = c.Params.Get("gnb-name"); !exists { + configLog.Infof("Post gNB request is missing gnb-name") + return false + } + configLog.Infof("Received gNB %v", gnbName) + var err error + var request configmodels.Gnb + + s := strings.Split(c.GetHeader("Content-Type"), ";") + switch s[0] { + case "application/json": + err = c.ShouldBindJSON(&request) + } + if err != nil { + configLog.Infof(" err %v", err) + return false + } + req := httpwrapper.NewRequest(c.Request, request) + procReq := req.Body.(configmodels.Gnb) + + var msg configmodels.ConfigMessage + procReq.GnbName = gnbName + msg.MsgType = configmodels.Inventory + msg.MsgMethod = configmodels.Post_op + msg.Gnb = &procReq + msg.GnbName = gnbName + configChannel <- &msg + configLog.Infof("Successfully added gNB [%v] to config channel.", gnbName) + return true +} + +func gnbDeletetHandler(c *gin.Context) bool { + var gnbName string + var exists bool + if gnbName, exists = c.Params.Get("gnb-name"); !exists { + configLog.Infof("Delete gNB request is missing gnb-name") + return false + } + configLog.Infof("Received Delete gNB %v", gnbName) + var msg configmodels.ConfigMessage + msg.MsgType = configmodels.Inventory + msg.MsgMethod = configmodels.Delete_op + msg.GnbName = gnbName + configChannel <- &msg + configLog.Infof("Successfully added gNB [%v] with delete_op to config channel.", gnbName) + return true +} + +func GetUpfs(c *gin.Context) { + setCorsHeader(c) + logger.WebUILog.Infoln("Get all UPFs") + + rawUpfs, errGetMany := dbadapter.CommonDBClient.RestfulAPIGetMany(upfDataColl, bson.M{}) + if errGetMany != nil { + logger.DbLog.Warnln(errGetMany) + } + + var upfs []*configmodels.Upf + for _, rawUpf := range rawUpfs { + var upfData configmodels.Upf + err := json.Unmarshal(mapToByte(rawUpf), &upfData) + if err != nil { + logger.DbLog.Errorf("Could not unmarshall UPF %v", rawUpf) + } + upfs = append(upfs, &upfData) + } + c.JSON(http.StatusOK, upfs) +} + +func UpfPostByName(c *gin.Context) { + logger.ConfigLog.Debugf("Received UpfPostByName ") + if ret := upfPostHandler(c); ret == true { + c.JSON(http.StatusOK, gin.H{}) + } else { + c.JSON(http.StatusBadRequest, gin.H{}) + } +} + +func UpfDeleteByName(c *gin.Context) { + logger.ConfigLog.Debugf("Received UpfDeleteByName ") + if ret := upfDeletetHandler(c); ret == true { + c.JSON(http.StatusOK, gin.H{}) + } else { + c.JSON(http.StatusBadRequest, gin.H{}) + } +} + +func upfPostHandler(c *gin.Context) bool { + var upfHostname string + var exists bool + if upfHostname, exists = c.Params.Get("upf-hostname"); !exists { + configLog.Infof("Post UPF request is missing upf-hostname") + return false + } + configLog.Infof("Received UPF %v", upfHostname) + var err error + var request configmodels.Upf + + s := strings.Split(c.GetHeader("Content-Type"), ";") + switch s[0] { + case "application/json": + err = c.ShouldBindJSON(&request) + } + if err != nil { + configLog.Infof(" err %v", err) + return false + } + req := httpwrapper.NewRequest(c.Request, request) + procReq := req.Body.(configmodels.Upf) + + var msg configmodels.ConfigMessage + procReq.Hostname = upfHostname + msg.MsgType = configmodels.Inventory + msg.MsgMethod = configmodels.Post_op + msg.Upf = &procReq + msg.UpfHostname = upfHostname + configChannel <- &msg + configLog.Infof("Successfully added UPF [%v] to config channel.", upfHostname) + return true +} + +func upfDeletetHandler(c *gin.Context) bool { + var upfHostname string + var exists bool + if upfHostname, exists = c.Params.Get("upf-hostname"); !exists { + configLog.Infof("Delete UPF request is missing upf-hostname") + return false + } + configLog.Infof("Received Delete UPF %v", upfHostname) + var msg configmodels.ConfigMessage + msg.MsgType = configmodels.Inventory + msg.MsgMethod = configmodels.Delete_op + msg.UpfHostname = upfHostname + configChannel <- &msg + configLog.Infof("Successfully added UPF [%v] with delete_op to config channel.", upfHostname) + return true +} diff --git a/configapi/routers.go b/configapi/routers.go index 13e8b567..28527013 100644 --- a/configapi/routers.go +++ b/configapi/routers.go @@ -144,4 +144,40 @@ var routes = Routes{ "/network-slice/:slice-name", NetworkSliceSliceNamePut, }, + { + "GetGnbs", + http.MethodGet, + "/inventory/gnb", + GetGnbs, + }, + { + "GnbPostByName", + http.MethodPost, + "/inventory/gnb/:gnb-name", + GnbDeleteByName, + }, + { + "GnbDeleteByName", + http.MethodDelete, + "/inventory/gnb/:gnb-name", + GnbDeleteByName, + }, + { + "GetUpfs", + http.MethodGet, + "/inventory/upf", + GetUpfs, + }, + { + "UpfPostByName", + http.MethodPost, + "/inventory/upf/:upf-hostname", + UpfPostByName, + }, + { + "UpfDeleteByName", + http.MethodDelete, + "/inventory/upf/:upf-hostname", + UpfDeleteByName, + }, } diff --git a/configmodels/config_msg.go b/configmodels/config_msg.go index 1130aeaa..38023486 100644 --- a/configmodels/config_msg.go +++ b/configmodels/config_msg.go @@ -19,15 +19,20 @@ const ( Device_group = iota Network_slice Sub_data + Inventory ) type ConfigMessage struct { DevGroup *DeviceGroups Slice *Slice AuthSubData *models.AuthenticationSubscription + Gnb *Gnb + Upf *Upf DevGroupName string SliceName string Imsi string + GnbName string + UpfHostname string MsgType int MsgMethod int } diff --git a/configmodels/model_inventory.go b/configmodels/model_inventory.go new file mode 100644 index 00000000..b42148ff --- /dev/null +++ b/configmodels/model_inventory.go @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2024 Open Networking Foundation +// +// SPDX-License-Identifier: Apache-2.0 +// + +package configmodels + +type Gnb struct { + GnbName string `json:"gnbName"` + Tac string `json:"tac"` +} + +type Upf struct { + Hostname string `json:"hostname"` + Port string `json:"port"` +} \ No newline at end of file diff --git a/proto/server/configEvtHandler.go b/proto/server/configEvtHandler.go index 2d07f5e3..1c58f06c 100644 --- a/proto/server/configEvtHandler.go +++ b/proto/server/configEvtHandler.go @@ -29,6 +29,8 @@ const ( flowRuleDataColl = "policyData.ues.flowRule" devGroupDataColl = "webconsoleData.snapshots.devGroupData" sliceDataColl = "webconsoleData.snapshots.sliceData" + gnbDataColl = "webconsoleData.snapshots.gnbData" + upfDataColl = "webconsoleData.snapshots.upfData" ) var configLog *logrus.Entry @@ -82,7 +84,7 @@ func configHandler(configMsgChan chan *configmodels.ConfigMessage, configReceive } if configMsg.MsgMethod == configmodels.Post_op || configMsg.MsgMethod == configmodels.Put_op { - if !firstConfigRcvd && (configMsg.MsgType == configmodels.Device_group || configMsg.MsgType == configmodels.Network_slice) { + if !firstConfigRcvd && (configMsg.MsgType == configmodels.Device_group || configMsg.MsgType == configmodels.Network_slice || configMsg.MsgType == configmodels.Inventory) { configLog.Debugln("First config received from ROC") firstConfigRcvd = true configReceived <- true @@ -100,6 +102,16 @@ func configHandler(configMsgChan chan *configmodels.ConfigMessage, configReceive handleNetworkSlicePost(configMsg, subsUpdateChan) } + if configMsg.Gnb != nil { + configLog.Infof("Received gNB [%v] configuration from config channel", configMsg.GnbName) + handleGnbPost(configMsg) + } + + if configMsg.Upf != nil { + configLog.Infof("Received UPF [%v] configuration from config channel", configMsg.UpfHostname) + handleUpfPost(configMsg) + } + // loop through all clients and send this message to all clients if len(clientNFPool) == 0 { configLog.Infoln("No client available. No need to send config") @@ -110,7 +122,16 @@ func configHandler(configMsgChan chan *configmodels.ConfigMessage, configReceive } } else { var config5gMsg Update5GSubscriberMsg - if configMsg.MsgType != configmodels.Sub_data { + if configMsg.MsgType == configmodels.Inventory { + if configMsg.GnbName != "" { + configLog.Infof("Received delete gNB [%v] from config channel", configMsg.GnbName) + handleGnbDelete(configMsg) + } + if configMsg.UpfHostname != "" { + configLog.Infof("Received delete UPF [%v] from config channel", configMsg.UpfHostname) + handleUpfDelete(configMsg) + } + } else if configMsg.MsgType != configmodels.Sub_data { rwLock.Lock() // update config snapshot if configMsg.DevGroup == nil { @@ -200,6 +221,48 @@ func handleNetworkSlicePost(configMsg *configmodels.ConfigMessage, subsUpdateCha rwLock.Unlock() } +func handleGnbPost(configMsg *configmodels.ConfigMessage) { + rwLock.Lock() + filter := bson.M{"gnbName": configMsg.GnbName} + gnbDataBson := toBsonM(configMsg.Gnb) + _, errPost := dbadapter.CommonDBClient.RestfulAPIPost(gnbDataColl, filter, gnbDataBson) + if errPost != nil { + logger.DbLog.Warnln(errPost) + } + rwLock.Unlock() +} + +func handleGnbDelete(configMsg *configmodels.ConfigMessage) { + rwLock.Lock() + filter := bson.M{"gnbName": configMsg.GnbName} + errDelOne := dbadapter.CommonDBClient.RestfulAPIDeleteOne(gnbDataColl, filter) + if errDelOne != nil { + logger.DbLog.Warnln(errDelOne) + } + rwLock.Unlock() +} + +func handleUpfPost(configMsg *configmodels.ConfigMessage) { + rwLock.Lock() + filter := bson.M{"hostname": configMsg.UpfHostname} + upfDataBson := toBsonM(configMsg.Upf) + _, errPost := dbadapter.CommonDBClient.RestfulAPIPost(upfDataColl, filter, upfDataBson) + if errPost != nil { + logger.DbLog.Warnln(errPost) + } + rwLock.Unlock() +} + +func handleUpfDelete(configMsg *configmodels.ConfigMessage) { + rwLock.Lock() + filter := bson.M{"hostname": configMsg.UpfHostname} + errDelOne := dbadapter.CommonDBClient.RestfulAPIDeleteOne(upfDataColl, filter) + if errDelOne != nil { + logger.DbLog.Warnln(errDelOne) + } + rwLock.Unlock() +} + func firstConfigReceived() bool { return len(getDeviceGroups()) > 0 || len(getSlices()) > 0 }