2 ==================================================================================
3 Copyright (c) 2019 AT&T Intellectual Property.
4 Copyright (c) 2019 Nokia
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
19 This source code is part of the near-RT RIC (RAN Intelligent Controller)
20 platform project (RICP).
22 ==================================================================================
25 Mnemonic: httprestful.go
26 Abstract: HTTP Restful API NBI implementation
27 Based on Swagger generated code
33 //noinspection GoUnresolvedReference,GoUnresolvedReference,GoUnresolvedReference,GoUnresolvedReference,GoUnresolvedReference,GoUnresolvedReference
38 xfmodel "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/models"
39 "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
40 //"github.com/go-openapi/loads"
41 //"github.com/go-openapi/runtime/middleware"
45 "routing-manager/pkg/models"
46 //"routing-manager/pkg/restapi"
47 //"routing-manager/pkg/restapi/operations"
48 //"routing-manager/pkg/restapi/operations/debug"
49 //"routing-manager/pkg/restapi/operations/handle"
50 "routing-manager/pkg/rpe"
51 "routing-manager/pkg/rtmgr"
52 "routing-manager/pkg/sdl"
59 type HttpRestful struct {
61 //LaunchRest LaunchRestHandler
62 RetrieveStartupData RetrieveStartupDataHandler
65 func NewHttpRestful() *HttpRestful {
66 instance := new(HttpRestful)
67 //instance.LaunchRest = launchRest
68 instance.RetrieveStartupData = retrieveStartupData
72 func recvXappCallbackData(xappData *models.XappCallbackData) (*[]rtmgr.XApp, error) {
74 var xapps []rtmgr.XApp
75 err := json.Unmarshal([]byte(xappData.XApps), &xapps)
78 xapp.Logger.Info("No data")
81 xapp.Logger.Debug("Nothing received on the Http interface")
85 func recvNewE2Tdata(e2tData *models.E2tData) (*rtmgr.E2TInstance, string, error) {
87 xapp.Logger.Info("Data received")
91 e2tinst := rtmgr.E2TInstance{
92 Ranlist: make([]string, len(e2tData.RanNamelist)),
95 e2tinst.Fqdn = *e2tData.E2TAddress
96 e2tinst.Name = "E2TERMINST"
97 copy(e2tinst.Ranlist, e2tData.RanNamelist)
98 if len(e2tData.RanNamelist) > 0 {
100 for _, meid := range e2tData.RanNamelist {
103 str = "mme_ar|" + *e2tData.E2TAddress + "|" + strings.TrimSuffix(meidar, " ")
105 return &e2tinst, str, nil
108 xapp.Logger.Info("No data")
111 xapp.Logger.Debug("Nothing received on the Http interface")
115 func validateXappCallbackData(callbackData *models.XappCallbackData) error {
116 if len(callbackData.XApps) == 0 {
117 return fmt.Errorf("invalid Data field: \"%s\"", callbackData.XApps)
119 var xapps []rtmgr.XApp
120 err := json.Unmarshal([]byte(callbackData.XApps), &xapps)
122 return fmt.Errorf("unmarshal failed: \"%s\"", err.Error())
127 func ProvideXappHandleHandlerImpl(data *models.XappCallbackData) error {
129 xapp.Logger.Debug("Received callback data")
132 err := validateXappCallbackData(data)
134 xapp.Logger.Warn("XApp callback data validation failed: " + err.Error())
137 appdata, err := recvXappCallbackData(data)
139 xapp.Logger.Error("Cannot get data from rest api dute to: " + err.Error())
140 } else if appdata != nil {
141 xapp.Logger.Debug("Fetching all xApps deployed in xApp Manager through GET operation")
142 alldata, err1 := httpGetXApps(xapp.Config.GetString("xmurl"))
143 if alldata != nil && err1 == nil {
145 sdlEngine.WriteXApps(xapp.Config.GetString("rtfile"), alldata)
148 return sendRoutesToAll()
149 //return sendPartialRoutesToAll(nil, rtmgr.XappType)
157 func validateXappSubscriptionData(data *models.XappSubscriptionData) error {
158 var err = fmt.Errorf("XApp instance not found: %v:%v", *data.Address, *data.Port)
159 for _, ep := range rtmgr.Eps {
160 if ep.Ip == *data.Address && ep.Port == *data.Port {
168 func validateE2tData(data *models.E2tData) (error, bool) {
170 e2taddress_key := *data.E2TAddress
171 if e2taddress_key == "" {
172 return fmt.Errorf("E2TAddress is empty!!!"), false
174 stringSlice := strings.Split(e2taddress_key, ":")
175 if len(stringSlice) == 1 {
176 return fmt.Errorf("E2T E2TAddress is not a proper format like ip:port, %v", e2taddress_key), false
179 _, err := net.LookupIP(stringSlice[0])
181 return fmt.Errorf("E2T E2TAddress DNS look up failed, E2TAddress: %v", stringSlice[0]), false
184 if checkValidaE2TAddress(e2taddress_key) {
185 return fmt.Errorf("E2TAddress already exist!!!, E2TAddress: %v", e2taddress_key), true
191 func validateDeleteE2tData(data *models.E2tDeleteData) error {
193 if *data.E2TAddress == "" {
194 return fmt.Errorf("E2TAddress is empty!!!")
197 for _, element := range data.RanAssocList {
198 e2taddress_key := *element.E2TAddress
199 stringSlice := strings.Split(e2taddress_key, ":")
201 if len(stringSlice) == 1 {
202 return fmt.Errorf("E2T Delete - RanAssocList E2TAddress is not a proper format like ip:port, %v", e2taddress_key)
205 if !checkValidaE2TAddress(e2taddress_key) {
206 return fmt.Errorf("E2TAddress doesn't exist!!!, E2TAddress: %v", e2taddress_key)
213 func checkValidaE2TAddress(e2taddress string) bool {
215 _, exist := rtmgr.Eps[e2taddress]
220 func ProvideXappSubscriptionHandleImpl(data *models.XappSubscriptionData) error {
221 xapp.Logger.Debug("Invoked provideXappSubscriptionHandleImpl")
222 err := validateXappSubscriptionData(data)
224 xapp.Logger.Error(err.Error())
227 xapp.Logger.Debug("Received xApp subscription data")
228 addSubscription(&rtmgr.Subs, data)
229 xapp.Logger.Debug("Endpoints: %v", rtmgr.Eps)
231 return sendPartialRoutesToAll(data, rtmgr.SubsType)
234 func subscriptionExists(data *models.XappSubscriptionData) bool {
236 sub := rtmgr.Subscription{SubID: *data.SubscriptionID, Fqdn: *data.Address, Port: *data.Port}
237 for _, elem := range rtmgr.Subs {
246 func DeleteXappSubscriptionHandleImpl(data *models.XappSubscriptionData) error {
247 xapp.Logger.Debug("Invoked deleteXappSubscriptionHandleImpl")
248 err := validateXappSubscriptionData(data)
250 xapp.Logger.Error(err.Error())
254 if !subscriptionExists(data) {
255 xapp.Logger.Warn("Subscription not found: %d", *data.SubscriptionID)
256 err := fmt.Errorf("Subscription not found: %d", *data.SubscriptionID)
260 xapp.Logger.Debug("Received xApp subscription delete data")
261 delSubscription(&rtmgr.Subs, data)
263 return sendRoutesToAll()
267 func UpdateXappSubscriptionHandleImpl(data *models.XappList, subid uint16) error {
268 xapp.Logger.Debug("Invoked updateXappSubscriptionHandleImpl")
270 var fqdnlist []rtmgr.FqDn
271 for _, item := range *data {
272 fqdnlist = append(fqdnlist, rtmgr.FqDn(*item))
274 xapplist := rtmgr.XappList{SubscriptionID: subid, FqdnList: fqdnlist}
275 var subdata models.XappSubscriptionData
278 subdata.SubscriptionID = &id
279 for _, items := range fqdnlist {
280 subdata.Address = items.Address
281 subdata.Port = items.Port
282 err := validateXappSubscriptionData(&subdata)
284 xapp.Logger.Error(err.Error())
288 xapp.Logger.Debug("Received XApp subscription Merge data")
289 updateSubscription(&xapplist)
291 return sendRoutesToAll()
294 func CreateNewE2tHandleHandlerImpl(data *models.E2tData) error {
295 xapp.Logger.Debug("Invoked createNewE2tHandleHandlerImpl")
296 err, IsDuplicate := validateE2tData(data)
297 if IsDuplicate == true {
299 //return sendPartialRoutesToAll(nil, rtmgr.E2Type)
300 return sendRoutesToAll()
304 xapp.Logger.Error(err.Error())
308 e2data, meiddata, _ := recvNewE2Tdata(data)
309 xapp.Logger.Debug("Received create New E2T data")
311 sdlEngine.WriteNewE2TInstance(xapp.Config.GetString("rtfile"), e2data, meiddata)
314 //sendPartialRoutesToAll(nil, rtmgr.E2Type)
316 time.Sleep(10 * time.Second)
317 for ep, value := range rtmgr.RMRConnStatus {
318 if ep == *data.E2TAddress && value == true {
319 rtmgr.RMRConnStatus[ep] = false //Reset to false incase of E2t restart scenario
324 return errors.New("Error while adding new E2T " + *data.E2TAddress)
328 func validateE2TAddressRANListData(assRanE2tData models.RanE2tMap) error {
330 xapp.Logger.Debug("Invoked.validateE2TAddressRANListData : %v", assRanE2tData)
332 for _, element := range assRanE2tData {
333 if *element.E2TAddress == "" {
334 return fmt.Errorf("E2T Instance - E2TAddress is empty!!!")
337 e2taddress_key := *element.E2TAddress
338 if !checkValidaE2TAddress(e2taddress_key) {
339 return fmt.Errorf("E2TAddress doesn't exist!!!, E2TAddress: %v", e2taddress_key)
346 func AssociateRanToE2THandlerImpl(data models.RanE2tMap) error {
347 xapp.Logger.Debug("Invoked associateRanToE2THandlerImpl")
348 err := validateE2TAddressRANListData(data)
350 xapp.Logger.Warn(" Association of RAN to E2T Instance data validation failed: " + err.Error())
353 xapp.Logger.Debug("Received associate RAN list to E2T instance mapping from E2 Manager")
355 sdlEngine.WriteAssRANToE2TInstance(xapp.Config.GetString("rtfile"), data)
358 return sendRoutesToAll()
362 func DisassociateRanToE2THandlerImpl(data models.RanE2tMap) error {
363 xapp.Logger.Debug("Invoked disassociateRanToE2THandlerImpl")
364 err := validateE2TAddressRANListData(data)
366 xapp.Logger.Warn(" Disassociation of RAN List from E2T Instance data validation failed: " + err.Error())
369 xapp.Logger.Debug("Received disassociate RANs from E2T instance")
371 sdlEngine.WriteDisAssRANFromE2TInstance(xapp.Config.GetString("rtfile"), data)
374 return sendRoutesToAll()
378 func DeleteE2tHandleHandlerImpl(data *models.E2tDeleteData) error {
379 xapp.Logger.Debug("Invoked deleteE2tHandleHandlerImpl")
381 err := validateDeleteE2tData(data)
383 xapp.Logger.Error(err.Error())
387 sdlEngine.WriteDeleteE2TInstance(xapp.Config.GetString("rtfile"), data)
390 return sendRoutesToAll()
394 func DumpDebugData() (models.Debuginfo, error) {
395 var response models.Debuginfo
396 sdlEngine, _ := sdl.GetSdl("file")
397 rpeEngine, _ := rpe.GetRpe("rmrpush")
398 data, err := sdlEngine.ReadAll(xapp.Config.GetString("rtfile"))
401 xapp.Logger.Error("Cannot get data from sdl interface due to: " + err.Error())
404 xapp.Logger.Debug("Cannot get data from sdl interface")
405 return response, errors.New("Cannot get data from sdl interface")
408 response.RouteTable = *rpeEngine.GeneratePolicies(rtmgr.Eps, data)
410 prettyJSON, err := json.MarshalIndent(data, "", "")
411 response.RouteConfigs = string(prettyJSON)
416 func httpGetXApps(xmurl string) (*[]rtmgr.XApp, error) {
417 xapp.Logger.Info("Invoked httprestful.httpGetXApps: " + xmurl)
418 r, err := myClient.Get(xmurl)
424 if r.StatusCode == 200 {
425 xapp.Logger.Debug("http client raw response: %v", r)
426 var xapps []rtmgr.XApp
427 err = json.NewDecoder(r.Body).Decode(&xapps)
429 xapp.Logger.Warn("Json decode failed: " + err.Error())
431 xapp.Logger.Info("HTTP GET: OK")
432 xapp.Logger.Debug("httprestful.httpGetXApps returns: %v", xapps)
435 xapp.Logger.Warn("httprestful got an unexpected http status code: %v", r.StatusCode)
439 func httpGetE2TList(e2murl string) (*[]rtmgr.E2tIdentity, error) {
440 xapp.Logger.Info("Invoked httprestful.httpGetE2TList: " + e2murl)
441 r, err := myClient.Get(e2murl)
447 if r.StatusCode == 200 {
448 xapp.Logger.Debug("http client raw response: %v", r)
449 var E2Tlist []rtmgr.E2tIdentity
450 err = json.NewDecoder(r.Body).Decode(&E2Tlist)
452 xapp.Logger.Warn("Json decode failed: " + err.Error())
454 xapp.Logger.Info("HTTP GET: OK")
455 xapp.Logger.Debug("httprestful.httpGetE2TList returns: %v", E2Tlist)
458 xapp.Logger.Warn("httprestful got an unexpected http status code: %v", r.StatusCode)
462 func PopulateE2TMap(e2tDataList *[]rtmgr.E2tIdentity, e2ts map[string]rtmgr.E2TInstance, meids *[]string) {
463 xapp.Logger.Info("Invoked httprestful.PopulateE2TMap ")
465 for _, e2tData := range *e2tDataList {
468 e2tinst := rtmgr.E2TInstance{
469 Ranlist: make([]string, len(e2tData.Rannames)),
472 e2tinst.Fqdn = e2tData.E2taddress
473 e2tinst.Name = "E2TERMINST"
474 copy(e2tinst.Ranlist, e2tData.Rannames)
476 if len(e2tData.Rannames) > 0 {
478 for _, meid := range e2tData.Rannames {
481 str = "mme_ar|" + e2tData.E2taddress + "|" + strings.TrimSuffix(meidar, " ")
482 *meids = append(*meids, str)
485 e2ts[e2tinst.Fqdn] = e2tinst
487 xapp.Logger.Info("MEID's retrieved are %v", *meids)
490 func retrieveStartupData(xmurl string, nbiif string, fileName string, configfile string, e2murl string, sdlEngine sdl.Engine) error {
491 xapp.Logger.Info("Invoked retrieveStartupData ")
495 var xappData *[]rtmgr.XApp
496 xappData = new([]rtmgr.XApp)
497 xapp.Logger.Info("Trying to fetch XApps data from XAPP manager")
498 for i := 1; i <= maxRetries; i++ {
499 time.Sleep(2 * time.Second)
502 xappData, err = httpGetXApps(xmurl)
503 if xappData != nil && err == nil {
505 } else if err == nil {
506 readErr = errors.New("unexpected HTTP status code")
508 xapp.Logger.Warn("Cannot get xapp data due to: " + err.Error())
518 e2ts := make(map[string]rtmgr.E2TInstance)
519 xapp.Logger.Info("Trying to fetch E2T data from E2manager")
520 for i := 1; i <= maxRetries; i++ {
523 e2tDataList, err := httpGetE2TList(e2murl)
524 if e2tDataList != nil && err == nil {
525 PopulateE2TMap(e2tDataList, e2ts, &meids)
527 } else if err == nil {
528 readErr = errors.New("unexpected HTTP status code")
530 xapp.Logger.Warn("Cannot get E2T data from E2M due to: " + err.Error())
533 time.Sleep(2 * time.Second)
540 pcData, confErr := rtmgr.GetPlatformComponents(configfile)
542 xapp.Logger.Error(confErr.Error())
545 xapp.Logger.Info("Recieved intial xapp data, E2T data and platform data, writing into SDL.")
546 // Combine the xapps data and platform data before writing to the SDL
547 ricData := &rtmgr.RicComponents{XApps: *xappData, Pcs: *pcData, E2Ts: e2ts, MeidMap: meids}
548 writeErr := sdlEngine.WriteAll(fileName, ricData)
550 xapp.Logger.Error(writeErr.Error())
553 xapp.Logger.Info("Trying to fetch Subscriptions data from Subscription manager")
554 for i := 1; i <= maxRetries; i++ {
556 sub_list, err := xapp.Subscription.QuerySubscriptions()
558 if sub_list != nil && err == nil {
559 PopulateSubscription(sub_list)
563 xapp.Logger.Warn("Cannot get xapp data due to: " + readErr.Error())
565 time.Sleep(2 * time.Second)
572 // post subscription req to appmgr
573 readErr = PostSubReq(xmurl, nbiif)
578 //rlist := make(map[string]string)
579 xapp.Logger.Info("Reading SDL for any routes")
580 rlist, sdlerr := xapp.SdlStorage.Read(rtmgr.RTMGR_SDL_NS, "routes")
583 xapp.Logger.Info("Value is %s", rlist["routes"])
584 if rlist["routes"] != nil {
585 formstring := fmt.Sprintf("%s", rlist["routes"])
586 xapp.Logger.Info("Value of formed string = %s", formstring)
587 newstring := strings.Split(formstring, " ")
588 for i, _ := range newstring {
589 xapp.Logger.Info("Value of formed string in loop = %s", newstring)
590 rtmgr.DynamicRouteList = append(rtmgr.DynamicRouteList, newstring[i])
600 func (r *HttpRestful) Initialize(xmurl string, nbiif string, fileName string, configfile string, e2murl string,
601 sdlEngine sdl.Engine, rpeEngine rpe.Engine, m *sync.Mutex) error {
602 err := r.RetrieveStartupData(xmurl, nbiif, fileName, configfile, e2murl, sdlEngine)
604 xapp.Logger.Error("Exiting as nbi failed to get the initial startup data from the xapp manager: " + err.Error())
611 func (r *HttpRestful) Terminate() error {
615 func addSubscription(subs *rtmgr.SubscriptionList, xappSubData *models.XappSubscriptionData) bool {
616 xapp.Logger.Debug("Adding the subscription into the subscriptions list")
618 sub := rtmgr.Subscription{SubID: *xappSubData.SubscriptionID, Fqdn: *xappSubData.Address, Port: *xappSubData.Port}
619 for _, elem := range *subs {
621 xapp.Logger.Warn("rtmgr.addSubscription: Subscription already present: %v", elem)
626 *subs = append(*subs, sub)
631 func delSubscription(subs *rtmgr.SubscriptionList, xappSubData *models.XappSubscriptionData) bool {
632 xapp.Logger.Debug("Deleteing the subscription from the subscriptions list")
634 sub := rtmgr.Subscription{SubID: *xappSubData.SubscriptionID, Fqdn: *xappSubData.Address, Port: *xappSubData.Port}
635 for i, elem := range *subs {
638 // Since the order of the list is not important, we are swapping the last element
639 // with the matching element and replacing the list with list(n-1) elements.
640 (*subs)[len(*subs)-1], (*subs)[i] = (*subs)[i], (*subs)[len(*subs)-1]
641 *subs = (*subs)[:len(*subs)-1]
645 if present == false {
646 xapp.Logger.Warn("rtmgr.delSubscription: Subscription = %v, not present in the existing subscriptions", xappSubData)
651 func updateSubscription(data *rtmgr.XappList) {
653 var subdata models.XappSubscriptionData
655 var matchingsubid, deletecount uint8
656 id = int32(data.SubscriptionID)
657 subdata.SubscriptionID = &id
658 for _, subs := range rtmgr.Subs {
659 if int32(data.SubscriptionID) == subs.SubID {
664 for deletecount < matchingsubid {
665 for _, subs := range rtmgr.Subs {
666 if int32(data.SubscriptionID) == subs.SubID {
667 subdata.SubscriptionID = &subs.SubID
668 subdata.Address = &subs.Fqdn
669 subdata.Port = &subs.Port
670 xapp.Logger.Debug("Deleting Subscription List has %v", subdata)
671 delSubscription(&rtmgr.Subs, &subdata)
678 for _, items := range data.FqdnList {
679 subdata.Address = items.Address
680 subdata.Port = items.Port
681 xapp.Logger.Debug("Adding Subscription List has %v", subdata)
682 addSubscription(&rtmgr.Subs, &subdata)
687 func PopulateSubscription(sub_list xfmodel.SubscriptionList) {
688 for _, sub_row := range sub_list {
689 var subdata models.XappSubscriptionData
690 id := int32(sub_row.SubscriptionID)
691 subdata.SubscriptionID = &id
692 for _, ep := range sub_row.ClientEndpoint {
693 stringSlice := strings.Split(ep, ":")
694 subdata.Address = &stringSlice[0]
695 intportval, _ := strconv.Atoi(stringSlice[1])
696 value := uint16(intportval)
697 subdata.Port = &value
698 xapp.Logger.Debug("Adding Subscription List has Address :%v, port :%v, SubscriptionID :%v ", subdata.Address, subdata.Address, subdata.SubscriptionID)
699 addSubscription(&rtmgr.Subs, &subdata)
704 func Adddelrmrroute(routelist models.Routelist, rtflag bool) error {
705 xapp.Logger.Info("Updating rmr route with Route list: %v,flag: %v", routelist, rtflag)
706 for _, rlist := range routelist {
709 if rlist.SubscriptionID == 0 {
712 subid = rlist.SubscriptionID
714 if rlist.SenderEndPoint == "" && rlist.SubscriptionID != 0 {
715 data = fmt.Sprintf("mse|%d|%d|%s\n", *rlist.MessageType, rlist.SubscriptionID, *rlist.TargetEndPoint)
716 } else if rlist.SenderEndPoint == "" && rlist.SubscriptionID == 0 {
717 data = fmt.Sprintf("mse|%d|-1|%s\n", *rlist.MessageType, *rlist.TargetEndPoint)
719 data = fmt.Sprintf("mse|%d,%s|%d|%s\n", *rlist.MessageType, rlist.SenderEndPoint, subid, *rlist.TargetEndPoint)
721 err := checkrepeatedroute(data)
725 xapp.Logger.Info("Given route %s is a duplicate", data)
727 rtmgr.DynamicRouteList = append(rtmgr.DynamicRouteList, data)
728 routearray := strings.Join(rtmgr.DynamicRouteList, " ")
729 xapp.SdlStorage.Store(rtmgr.RTMGR_SDL_NS, "routes", routearray)
732 xapp.Logger.Info("route %s deleted successfully", data)
733 routearray := strings.Join(rtmgr.DynamicRouteList, " ")
734 xapp.SdlStorage.Store(rtmgr.RTMGR_SDL_NS, "routes", routearray)
736 xapp.Logger.Info("No such route: %s", data)
737 return errors.New("No such route: " + data)
743 return sendRoutesToAll()
746 func checkrepeatedroute(data string) bool {
747 for i := 0; i < len(rtmgr.DynamicRouteList); i++ {
748 if rtmgr.DynamicRouteList[i] == data {
749 rtmgr.DynamicRouteList[i] = rtmgr.DynamicRouteList[len(rtmgr.DynamicRouteList)-1]
750 rtmgr.DynamicRouteList[len(rtmgr.DynamicRouteList)-1] = ""
751 rtmgr.DynamicRouteList = rtmgr.DynamicRouteList[:len(rtmgr.DynamicRouteList)-1]