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/sbi"
53 "routing-manager/pkg/sdl"
60 type HttpRestful struct {
62 //LaunchRest LaunchRestHandler
63 RetrieveStartupData RetrieveStartupDataHandler
66 func NewHttpRestful() *HttpRestful {
67 instance := new(HttpRestful)
68 //instance.LaunchRest = launchRest
69 instance.RetrieveStartupData = retrieveStartupData
73 func recvXappCallbackData(xappData *models.XappCallbackData) (*[]rtmgr.XApp, error) {
75 var xapps []rtmgr.XApp
76 err := json.Unmarshal([]byte(xappData.XApps), &xapps)
79 xapp.Logger.Info("No data")
82 xapp.Logger.Debug("Nothing received on the Http interface")
86 func recvNewE2Tdata(e2tData *models.E2tData) (*rtmgr.E2TInstance, string, error) {
88 xapp.Logger.Info("Data received")
92 e2tinst := rtmgr.E2TInstance{
93 Ranlist: make([]string, len(e2tData.RanNamelist)),
96 e2tinst.Fqdn = *e2tData.E2TAddress
97 e2tinst.Name = "E2TERMINST"
98 copy(e2tinst.Ranlist, e2tData.RanNamelist)
99 if len(e2tData.RanNamelist) > 0 {
101 for _, meid := range e2tData.RanNamelist {
104 str = "mme_ar|" + *e2tData.E2TAddress + "|" + strings.TrimSuffix(meidar, " ")
106 return &e2tinst, str, nil
109 xapp.Logger.Info("No data")
112 xapp.Logger.Debug("Nothing received on the Http interface")
116 func validateXappCallbackData(callbackData *models.XappCallbackData) error {
117 if len(callbackData.XApps) == 0 {
118 return fmt.Errorf("invalid Data field: \"%s\"", callbackData.XApps)
120 var xapps []rtmgr.XApp
121 err := json.Unmarshal([]byte(callbackData.XApps), &xapps)
123 return fmt.Errorf("unmarshal failed: \"%s\"", err.Error())
128 func ProvideXappHandleHandlerImpl(data *models.XappCallbackData) error {
130 xapp.Logger.Debug("Received callback data")
133 err := validateXappCallbackData(data)
135 xapp.Logger.Warn("XApp callback data validation failed: " + err.Error())
138 appdata, err := recvXappCallbackData(data)
140 xapp.Logger.Error("Cannot get data from rest api dute to: " + err.Error())
141 } else if appdata != nil {
142 xapp.Logger.Debug("Fetching all xApps deployed in xApp Manager through GET operation")
143 alldata, err1 := httpGetXApps(xapp.Config.GetString("xmurl"))
144 if alldata != nil && err1 == nil {
146 sdlEngine.WriteXApps(xapp.Config.GetString("rtfile"), alldata)
149 return sendRoutesToAll()
150 //return sendPartialRoutesToAll(nil, rtmgr.XappType)
158 func validateXappSubscriptionData(data *models.XappSubscriptionData) error {
159 var err = fmt.Errorf("XApp instance not found: %v:%v", *data.Address, *data.Port)
160 for _, ep := range rtmgr.Eps {
161 if ep.Ip == *data.Address && ep.Port == *data.Port {
169 func validateE2tData(data *models.E2tData) (error, bool) {
171 e2taddress_key := *data.E2TAddress
172 if e2taddress_key == "" {
173 return fmt.Errorf("E2TAddress is empty!!!"), false
175 stringSlice := strings.Split(e2taddress_key, ":")
176 if len(stringSlice) == 1 {
177 return fmt.Errorf("E2T E2TAddress is not a proper format like ip:port, %v", e2taddress_key), false
180 _, err := net.LookupIP(stringSlice[0])
182 return fmt.Errorf("E2T E2TAddress DNS look up failed, E2TAddress: %v", stringSlice[0]), false
185 if checkValidaE2TAddress(e2taddress_key) {
186 return fmt.Errorf("E2TAddress already exist!!!, E2TAddress: %v", e2taddress_key), true
192 func validateDeleteE2tData(data *models.E2tDeleteData) error {
194 if *data.E2TAddress == "" {
195 return fmt.Errorf("E2TAddress is empty!!!")
198 for _, element := range data.RanAssocList {
199 e2taddress_key := *element.E2TAddress
200 stringSlice := strings.Split(e2taddress_key, ":")
202 if len(stringSlice) == 1 {
203 return fmt.Errorf("E2T Delete - RanAssocList E2TAddress is not a proper format like ip:port, %v", e2taddress_key)
206 if !checkValidaE2TAddress(e2taddress_key) {
207 return fmt.Errorf("E2TAddress doesn't exist!!!, E2TAddress: %v", e2taddress_key)
214 func checkValidaE2TAddress(e2taddress string) bool {
216 _, exist := rtmgr.Eps[e2taddress]
221 func ProvideXappSubscriptionHandleImpl(data *models.XappSubscriptionData) error {
222 xapp.Logger.Debug("Invoked provideXappSubscriptionHandleImpl")
223 err := validateXappSubscriptionData(data)
225 xapp.Logger.Error(err.Error())
228 xapp.Logger.Debug("Received xApp subscription data")
229 addSubscription(&rtmgr.Subs, data)
230 xapp.Logger.Debug("Endpoints: %v", rtmgr.Eps)
232 return sendPartialRoutesToAll(data, rtmgr.SubsType)
235 func subscriptionExists(data *models.XappSubscriptionData) bool {
237 sub := rtmgr.Subscription{SubID: *data.SubscriptionID, Fqdn: *data.Address, Port: *data.Port}
238 for _, elem := range rtmgr.Subs {
247 func DeleteXappSubscriptionHandleImpl(data *models.XappSubscriptionData) error {
248 xapp.Logger.Debug("Invoked deleteXappSubscriptionHandleImpl")
249 err := validateXappSubscriptionData(data)
251 xapp.Logger.Error(err.Error())
255 if !subscriptionExists(data) {
256 xapp.Logger.Warn("Subscription not found: %d", *data.SubscriptionID)
257 err := fmt.Errorf("Subscription not found: %d", *data.SubscriptionID)
261 xapp.Logger.Debug("Received xApp subscription delete data")
262 delSubscription(&rtmgr.Subs, data)
264 return sendRoutesToAll()
268 func UpdateXappSubscriptionHandleImpl(data *models.XappList, subid uint16) error {
269 xapp.Logger.Debug("Invoked updateXappSubscriptionHandleImpl")
271 var fqdnlist []rtmgr.FqDn
272 for _, item := range *data {
273 fqdnlist = append(fqdnlist, rtmgr.FqDn(*item))
275 xapplist := rtmgr.XappList{SubscriptionID: subid, FqdnList: fqdnlist}
276 var subdata models.XappSubscriptionData
279 subdata.SubscriptionID = &id
280 for _, items := range fqdnlist {
281 subdata.Address = items.Address
282 subdata.Port = items.Port
283 err := validateXappSubscriptionData(&subdata)
285 xapp.Logger.Error(err.Error())
289 xapp.Logger.Debug("Received XApp subscription Merge data")
290 updateSubscription(&xapplist)
292 return sendRoutesToAll()
295 func CreateNewE2tHandleHandlerImpl(data *models.E2tData) error {
296 xapp.Logger.Debug("Invoked createNewE2tHandleHandlerImpl")
297 err, IsDuplicate := validateE2tData(data)
298 if IsDuplicate == true {
300 //return sendPartialRoutesToAll(nil, rtmgr.E2Type)
301 return sendRoutesToAll()
305 xapp.Logger.Error(err.Error())
309 e2data, meiddata, _ := recvNewE2Tdata(data)
310 xapp.Logger.Debug("Received create New E2T data")
312 sdlEngine.WriteNewE2TInstance(xapp.Config.GetString("rtfile"), e2data, meiddata)
315 //sendPartialRoutesToAll(nil, rtmgr.E2Type)
317 rtmgr.RMRConnStatus[*data.E2TAddress] = false
321 time.Sleep(10 * time.Second)
322 if rtmgr.RMRConnStatus[*data.E2TAddress] == true {
324 delete(rtmgr.RMRConnStatus, *data.E2TAddress)
326 xapp.Logger.Debug("RMRConnStatus Map after = %v", rtmgr.RMRConnStatus)
330 return errors.New("Error while adding new E2T " + *data.E2TAddress)
334 func validateE2TAddressRANListData(assRanE2tData models.RanE2tMap) error {
336 xapp.Logger.Debug("Invoked.validateE2TAddressRANListData : %v", assRanE2tData)
338 for _, element := range assRanE2tData {
339 if *element.E2TAddress == "" {
340 return fmt.Errorf("E2T Instance - E2TAddress is empty!!!")
343 e2taddress_key := *element.E2TAddress
344 if !checkValidaE2TAddress(e2taddress_key) {
345 return fmt.Errorf("E2TAddress doesn't exist!!!, E2TAddress: %v", e2taddress_key)
352 func AssociateRanToE2THandlerImpl(data models.RanE2tMap) error {
353 xapp.Logger.Debug("Invoked associateRanToE2THandlerImpl")
354 err := validateE2TAddressRANListData(data)
356 xapp.Logger.Warn(" Association of RAN to E2T Instance data validation failed: " + err.Error())
359 xapp.Logger.Debug("Received associate RAN list to E2T instance mapping from E2 Manager")
361 sdlEngine.WriteAssRANToE2TInstance(xapp.Config.GetString("rtfile"), data)
364 return sendRoutesToAll()
368 func DisassociateRanToE2THandlerImpl(data models.RanE2tMap) error {
369 xapp.Logger.Debug("Invoked disassociateRanToE2THandlerImpl")
370 err := validateE2TAddressRANListData(data)
372 xapp.Logger.Warn(" Disassociation of RAN List from E2T Instance data validation failed: " + err.Error())
375 xapp.Logger.Debug("Received disassociate RANs from E2T instance")
377 sdlEngine.WriteDisAssRANFromE2TInstance(xapp.Config.GetString("rtfile"), data)
380 return sendRoutesToAll()
384 func DeleteE2tHandleHandlerImpl(data *models.E2tDeleteData) error {
385 xapp.Logger.Debug("Invoked deleteE2tHandleHandlerImpl")
387 err := validateDeleteE2tData(data)
389 xapp.Logger.Error(err.Error())
393 sdlEngine.WriteDeleteE2TInstance(xapp.Config.GetString("rtfile"), data)
396 return sendRoutesToAll()
400 func DumpDebugData() (models.Debuginfo, error) {
401 var response models.Debuginfo
402 sdlEngine, _ := sdl.GetSdl("file")
403 rpeEngine, _ := rpe.GetRpe("rmrpush")
404 data, err := sdlEngine.ReadAll(xapp.Config.GetString("rtfile"))
407 xapp.Logger.Error("Cannot get data from sdl interface due to: " + err.Error())
410 xapp.Logger.Debug("Cannot get data from sdl interface")
411 return response, errors.New("Cannot get data from sdl interface")
414 response.RouteTable = *rpeEngine.GeneratePolicies(rtmgr.Eps, data)
416 prettyJSON, err := json.MarshalIndent(data, "", "")
417 response.RouteConfigs = string(prettyJSON)
422 func httpGetXApps(xmurl string) (*[]rtmgr.XApp, error) {
423 xapp.Logger.Info("Invoked httprestful.httpGetXApps: " + xmurl)
424 r, err := myClient.Get(xmurl)
430 if r.StatusCode == 200 {
431 xapp.Logger.Debug("http client raw response: %v", r)
432 var xapps []rtmgr.XApp
433 err = json.NewDecoder(r.Body).Decode(&xapps)
435 xapp.Logger.Warn("Json decode failed: " + err.Error())
437 xapp.Logger.Info("HTTP GET: OK")
438 xapp.Logger.Debug("httprestful.httpGetXApps returns: %v", xapps)
441 xapp.Logger.Warn("httprestful got an unexpected http status code: %v", r.StatusCode)
445 func httpGetE2TList(e2murl string) (*[]rtmgr.E2tIdentity, error) {
446 xapp.Logger.Info("Invoked httprestful.httpGetE2TList: " + e2murl)
447 r, err := myClient.Get(e2murl)
453 if r.StatusCode == 200 {
454 xapp.Logger.Debug("http client raw response: %v", r)
455 var E2Tlist []rtmgr.E2tIdentity
456 err = json.NewDecoder(r.Body).Decode(&E2Tlist)
458 xapp.Logger.Warn("Json decode failed: " + err.Error())
460 xapp.Logger.Info("HTTP GET: OK")
461 xapp.Logger.Debug("httprestful.httpGetE2TList returns: %v", E2Tlist)
464 xapp.Logger.Warn("httprestful got an unexpected http status code: %v", r.StatusCode)
468 func PopulateE2TMap(e2tDataList *[]rtmgr.E2tIdentity, e2ts map[string]rtmgr.E2TInstance, meids *[]string) {
469 xapp.Logger.Info("Invoked httprestful.PopulateE2TMap ")
471 for _, e2tData := range *e2tDataList {
474 e2tinst := rtmgr.E2TInstance{
475 Ranlist: make([]string, len(e2tData.Rannames)),
478 e2tinst.Fqdn = e2tData.E2taddress
479 e2tinst.Name = "E2TERMINST"
480 copy(e2tinst.Ranlist, e2tData.Rannames)
482 if len(e2tData.Rannames) > 0 {
484 for _, meid := range e2tData.Rannames {
487 str = "mme_ar|" + e2tData.E2taddress + "|" + strings.TrimSuffix(meidar, " ")
488 *meids = append(*meids, str)
491 e2ts[e2tinst.Fqdn] = e2tinst
493 xapp.Logger.Info("MEID's retrieved are %v", *meids)
496 func retrieveStartupData(xmurl string, nbiif string, fileName string, configfile string, e2murl string, sdlEngine sdl.Engine) error {
497 xapp.Logger.Info("Invoked retrieveStartupData ")
501 var xappData *[]rtmgr.XApp
502 xappData = new([]rtmgr.XApp)
503 xapp.Logger.Info("Trying to fetch XApps data from XAPP manager")
504 for i := 1; i <= maxRetries; i++ {
505 time.Sleep(2 * time.Second)
508 xappData, err = httpGetXApps(xmurl)
509 if xappData != nil && err == nil {
511 } else if err == nil {
512 readErr = errors.New("unexpected HTTP status code")
514 xapp.Logger.Warn("Cannot get xapp data due to: " + err.Error())
524 e2ts := make(map[string]rtmgr.E2TInstance)
525 xapp.Logger.Info("Trying to fetch E2T data from E2manager")
526 for i := 1; i <= maxRetries; i++ {
529 e2tDataList, err := httpGetE2TList(e2murl)
530 if e2tDataList != nil && err == nil {
531 PopulateE2TMap(e2tDataList, e2ts, &meids)
533 } else if err == nil {
534 readErr = errors.New("unexpected HTTP status code")
536 xapp.Logger.Warn("Cannot get E2T data from E2M due to: " + err.Error())
539 time.Sleep(2 * time.Second)
546 pcData, confErr := rtmgr.GetPlatformComponents(configfile)
548 xapp.Logger.Error(confErr.Error())
551 xapp.Logger.Info("Recieved intial xapp data, E2T data and platform data, writing into SDL.")
552 // Combine the xapps data and platform data before writing to the SDL
553 ricData := &rtmgr.RicComponents{XApps: *xappData, Pcs: *pcData, E2Ts: e2ts, MeidMap: meids}
554 writeErr := sdlEngine.WriteAll(fileName, ricData)
556 xapp.Logger.Error(writeErr.Error())
559 xapp.Logger.Info("Trying to fetch Subscriptions data from Subscription manager")
560 for i := 1; i <= maxRetries; i++ {
562 sub_list, err := xapp.Subscription.QuerySubscriptions()
564 if sub_list != nil && err == nil {
565 PopulateSubscription(sub_list)
569 xapp.Logger.Warn("Cannot get xapp data due to: " + readErr.Error())
571 time.Sleep(2 * time.Second)
578 // post subscription req to appmgr
579 readErr = PostSubReq(xmurl, nbiif)
584 //rlist := make(map[string]string)
585 xapp.Logger.Info("Reading SDL for any routes")
586 rlist, sdlerr := xapp.SdlStorage.Read(rtmgr.RTMGR_SDL_NS, "routes")
589 xapp.Logger.Info("Value is %s", rlist["routes"])
590 if rlist["routes"] != nil {
591 formstring := fmt.Sprintf("%s", rlist["routes"])
592 xapp.Logger.Info("Value of formed string = %s", formstring)
593 newstring := strings.Split(formstring, " ")
594 for i, _ := range newstring {
595 xapp.Logger.Info("Value of formed string in loop = %s", newstring)
596 rtmgr.DynamicRouteList = append(rtmgr.DynamicRouteList, newstring[i])
606 func (r *HttpRestful) Initialize(xmurl string, nbiif string, fileName string, configfile string, e2murl string,
607 sdlEngine sdl.Engine, rpeEngine rpe.Engine, m *sync.Mutex) error {
608 err := r.RetrieveStartupData(xmurl, nbiif, fileName, configfile, e2murl, sdlEngine)
610 xapp.Logger.Error("Exiting as nbi failed to get the initial startup data from the xapp manager: " + err.Error())
617 func (r *HttpRestful) Terminate() error {
621 func addSubscription(subs *rtmgr.SubscriptionList, xappSubData *models.XappSubscriptionData) bool {
622 xapp.Logger.Debug("Adding the subscription into the subscriptions list")
624 sub := rtmgr.Subscription{SubID: *xappSubData.SubscriptionID, Fqdn: *xappSubData.Address, Port: *xappSubData.Port}
625 for _, elem := range *subs {
627 xapp.Logger.Warn("rtmgr.addSubscription: Subscription already present: %v", elem)
632 *subs = append(*subs, sub)
637 func delSubscription(subs *rtmgr.SubscriptionList, xappSubData *models.XappSubscriptionData) bool {
638 xapp.Logger.Debug("Deleteing the subscription from the subscriptions list")
640 sub := rtmgr.Subscription{SubID: *xappSubData.SubscriptionID, Fqdn: *xappSubData.Address, Port: *xappSubData.Port}
641 for i, elem := range *subs {
644 // Since the order of the list is not important, we are swapping the last element
645 // with the matching element and replacing the list with list(n-1) elements.
646 (*subs)[len(*subs)-1], (*subs)[i] = (*subs)[i], (*subs)[len(*subs)-1]
647 *subs = (*subs)[:len(*subs)-1]
651 if present == false {
652 xapp.Logger.Warn("rtmgr.delSubscription: Subscription = %v, not present in the existing subscriptions", xappSubData)
657 func updateSubscription(data *rtmgr.XappList) {
659 var subdata models.XappSubscriptionData
661 var matchingsubid, deletecount uint8
662 id = int32(data.SubscriptionID)
663 subdata.SubscriptionID = &id
664 for _, subs := range rtmgr.Subs {
665 if int32(data.SubscriptionID) == subs.SubID {
670 for deletecount < matchingsubid {
671 for _, subs := range rtmgr.Subs {
672 if int32(data.SubscriptionID) == subs.SubID {
673 subdata.SubscriptionID = &subs.SubID
674 subdata.Address = &subs.Fqdn
675 subdata.Port = &subs.Port
676 xapp.Logger.Debug("Deleting Subscription List has %v", subdata)
677 delSubscription(&rtmgr.Subs, &subdata)
684 for _, items := range data.FqdnList {
685 subdata.Address = items.Address
686 subdata.Port = items.Port
687 xapp.Logger.Debug("Adding Subscription List has %v", subdata)
688 addSubscription(&rtmgr.Subs, &subdata)
693 func PopulateSubscription(sub_list xfmodel.SubscriptionList) {
694 for _, sub_row := range sub_list {
695 var subdata models.XappSubscriptionData
696 id := int32(sub_row.SubscriptionID)
697 subdata.SubscriptionID = &id
698 for _, ep := range sub_row.ClientEndpoint {
699 stringSlice := strings.Split(ep, ":")
700 subdata.Address = &stringSlice[0]
701 intportval, _ := strconv.Atoi(stringSlice[1])
702 value := uint16(intportval)
703 subdata.Port = &value
704 xapp.Logger.Debug("Adding Subscription List has Address :%v, port :%v, SubscriptionID :%v ", subdata.Address, subdata.Address, subdata.SubscriptionID)
705 addSubscription(&rtmgr.Subs, &subdata)
710 func Adddelrmrroute(routelist models.Routelist, rtflag bool) error {
711 xapp.Logger.Info("Updating rmr route with Route list: %v,flag: %v", routelist, rtflag)
712 for _, rlist := range routelist {
715 if rlist.SubscriptionID == 0 {
718 subid = rlist.SubscriptionID
720 if rlist.SenderEndPoint == "" && rlist.SubscriptionID != 0 {
721 data = fmt.Sprintf("mse|%d|%d|%s\n", *rlist.MessageType, rlist.SubscriptionID, *rlist.TargetEndPoint)
722 } else if rlist.SenderEndPoint == "" && rlist.SubscriptionID == 0 {
723 data = fmt.Sprintf("mse|%d|-1|%s\n", *rlist.MessageType, *rlist.TargetEndPoint)
725 data = fmt.Sprintf("mse|%d,%s|%d|%s\n", *rlist.MessageType, rlist.SenderEndPoint, subid, *rlist.TargetEndPoint)
727 err := checkrepeatedroute(data)
731 xapp.Logger.Info("Given route %s is a duplicate", data)
733 rtmgr.DynamicRouteList = append(rtmgr.DynamicRouteList, data)
734 routearray := strings.Join(rtmgr.DynamicRouteList, " ")
735 xapp.SdlStorage.Store(rtmgr.RTMGR_SDL_NS, "routes", routearray)
738 xapp.Logger.Info("route %s deleted successfully", data)
739 routearray := strings.Join(rtmgr.DynamicRouteList, " ")
740 xapp.SdlStorage.Store(rtmgr.RTMGR_SDL_NS, "routes", routearray)
742 xapp.Logger.Info("No such route: %s", data)
743 return errors.New("No such route: " + data)
749 return sendRoutesToAll()
752 func checkrepeatedroute(data string) bool {
753 for i := 0; i < len(rtmgr.DynamicRouteList); i++ {
754 if rtmgr.DynamicRouteList[i] == data {
755 rtmgr.DynamicRouteList[i] = rtmgr.DynamicRouteList[len(rtmgr.DynamicRouteList)-1]
756 rtmgr.DynamicRouteList[len(rtmgr.DynamicRouteList)-1] = ""
757 rtmgr.DynamicRouteList = rtmgr.DynamicRouteList[:len(rtmgr.DynamicRouteList)-1]