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 {
323 return errors.New("Error while adding new E2T " + *data.E2TAddress)
327 func validateE2TAddressRANListData(assRanE2tData models.RanE2tMap) error {
329 xapp.Logger.Debug("Invoked.validateE2TAddressRANListData : %v", assRanE2tData)
331 for _, element := range assRanE2tData {
332 if *element.E2TAddress == "" {
333 return fmt.Errorf("E2T Instance - E2TAddress is empty!!!")
336 e2taddress_key := *element.E2TAddress
337 if !checkValidaE2TAddress(e2taddress_key) {
338 return fmt.Errorf("E2TAddress doesn't exist!!!, E2TAddress: %v", e2taddress_key)
345 func AssociateRanToE2THandlerImpl(data models.RanE2tMap) error {
346 xapp.Logger.Debug("Invoked associateRanToE2THandlerImpl")
347 err := validateE2TAddressRANListData(data)
349 xapp.Logger.Warn(" Association of RAN to E2T Instance data validation failed: " + err.Error())
352 xapp.Logger.Debug("received associate RAN list to E2T instance mapping from E2 Manager")
354 sdlEngine.WriteAssRANToE2TInstance(xapp.Config.GetString("rtfile"), data)
357 return sendRoutesToAll()
361 func DisassociateRanToE2THandlerImpl(data models.RanE2tMap) error {
362 xapp.Logger.Debug("Invoked disassociateRanToE2THandlerImpl")
363 err := validateE2TAddressRANListData(data)
365 xapp.Logger.Warn(" Disassociation of RAN List from E2T Instance data validation failed: " + err.Error())
368 xapp.Logger.Debug("received disassociate RANs from E2T instance")
370 sdlEngine.WriteDisAssRANFromE2TInstance(xapp.Config.GetString("rtfile"), data)
373 return sendRoutesToAll()
377 func DeleteE2tHandleHandlerImpl(data *models.E2tDeleteData) error {
378 xapp.Logger.Debug("Invoked deleteE2tHandleHandlerImpl")
380 err := validateDeleteE2tData(data)
382 xapp.Logger.Error(err.Error())
386 sdlEngine.WriteDeleteE2TInstance(xapp.Config.GetString("rtfile"), data)
389 return sendRoutesToAll()
393 func DumpDebugData() (models.Debuginfo, error) {
394 var response models.Debuginfo
395 sdlEngine, _ := sdl.GetSdl("file")
396 rpeEngine, _ := rpe.GetRpe("rmrpush")
397 data, err := sdlEngine.ReadAll(xapp.Config.GetString("rtfile"))
400 xapp.Logger.Error("Cannot get data from sdl interface due to: " + err.Error())
403 xapp.Logger.Debug("Cannot get data from sdl interface")
404 return response, errors.New("Cannot get data from sdl interface")
407 response.RouteTable = *rpeEngine.GeneratePolicies(rtmgr.Eps, data)
409 prettyJSON, err := json.MarshalIndent(data, "", "")
410 response.RouteConfigs = string(prettyJSON)
415 func httpGetXApps(xmurl string) (*[]rtmgr.XApp, error) {
416 xapp.Logger.Info("Invoked httprestful.httpGetXApps: " + xmurl)
417 r, err := myClient.Get(xmurl)
423 if r.StatusCode == 200 {
424 xapp.Logger.Debug("http client raw response: %v", r)
425 var xapps []rtmgr.XApp
426 err = json.NewDecoder(r.Body).Decode(&xapps)
428 xapp.Logger.Warn("Json decode failed: " + err.Error())
430 xapp.Logger.Info("HTTP GET: OK")
431 xapp.Logger.Debug("httprestful.httpGetXApps returns: %v", xapps)
434 xapp.Logger.Warn("httprestful got an unexpected http status code: %v", r.StatusCode)
438 func httpGetE2TList(e2murl string) (*[]rtmgr.E2tIdentity, error) {
439 xapp.Logger.Info("Invoked httprestful.httpGetE2TList: " + e2murl)
440 r, err := myClient.Get(e2murl)
446 if r.StatusCode == 200 {
447 xapp.Logger.Debug("http client raw response: %v", r)
448 var E2Tlist []rtmgr.E2tIdentity
449 err = json.NewDecoder(r.Body).Decode(&E2Tlist)
451 xapp.Logger.Warn("Json decode failed: " + err.Error())
453 xapp.Logger.Info("HTTP GET: OK")
454 xapp.Logger.Debug("httprestful.httpGetE2TList returns: %v", E2Tlist)
457 xapp.Logger.Warn("httprestful got an unexpected http status code: %v", r.StatusCode)
461 func PopulateE2TMap(e2tDataList *[]rtmgr.E2tIdentity, e2ts map[string]rtmgr.E2TInstance, meids *[]string) {
462 xapp.Logger.Info("Invoked httprestful.PopulateE2TMap ")
464 for _, e2tData := range *e2tDataList {
467 e2tinst := rtmgr.E2TInstance{
468 Ranlist: make([]string, len(e2tData.Rannames)),
471 e2tinst.Fqdn = e2tData.E2taddress
472 e2tinst.Name = "E2TERMINST"
473 copy(e2tinst.Ranlist, e2tData.Rannames)
475 if len(e2tData.Rannames) > 0 {
477 for _, meid := range e2tData.Rannames {
480 str = "mme_ar|" + e2tData.E2taddress + "|" + strings.TrimSuffix(meidar, " ")
481 *meids = append(*meids, str)
484 e2ts[e2tinst.Fqdn] = e2tinst
486 xapp.Logger.Info("MEID's retrieved are %v", *meids)
489 func retrieveStartupData(xmurl string, nbiif string, fileName string, configfile string, e2murl string, sdlEngine sdl.Engine) error {
490 xapp.Logger.Info("Invoked retrieveStartupData ")
494 var xappData *[]rtmgr.XApp
495 xappData = new([]rtmgr.XApp)
496 xapp.Logger.Info("Trying to fetch XApps data from XAPP manager")
497 for i := 1; i <= maxRetries; i++ {
498 time.Sleep(2 * time.Second)
501 xappData, err = httpGetXApps(xmurl)
502 if xappData != nil && err == nil {
504 } else if err == nil {
505 readErr = errors.New("unexpected HTTP status code")
507 xapp.Logger.Warn("cannot get xapp data due to: " + err.Error())
517 e2ts := make(map[string]rtmgr.E2TInstance)
518 xapp.Logger.Info("Trying to fetch E2T data from E2manager")
519 for i := 1; i <= maxRetries; i++ {
522 e2tDataList, err := httpGetE2TList(e2murl)
523 if e2tDataList != nil && err == nil {
524 PopulateE2TMap(e2tDataList, e2ts, &meids)
526 } else if err == nil {
527 readErr = errors.New("unexpected HTTP status code")
529 xapp.Logger.Warn("cannot get E2T data from E2M due to: " + err.Error())
532 time.Sleep(2 * time.Second)
539 pcData, confErr := rtmgr.GetPlatformComponents(configfile)
541 xapp.Logger.Error(confErr.Error())
544 xapp.Logger.Info("Recieved intial xapp data, E2T data and platform data, writing into SDL.")
545 // Combine the xapps data and platform data before writing to the SDL
546 ricData := &rtmgr.RicComponents{XApps: *xappData, Pcs: *pcData, E2Ts: e2ts, MeidMap: meids}
547 writeErr := sdlEngine.WriteAll(fileName, ricData)
549 xapp.Logger.Error(writeErr.Error())
552 xapp.Logger.Info("Trying to fetch Subscriptions data from Subscription manager")
553 for i := 1; i <= maxRetries; i++ {
555 sub_list, err := xapp.Subscription.QuerySubscriptions()
557 if sub_list != nil && err == nil {
558 PopulateSubscription(sub_list)
562 xapp.Logger.Warn("cannot get xapp data due to: " + readErr.Error())
564 time.Sleep(2 * time.Second)
571 // post subscription req to appmgr
572 readErr = PostSubReq(xmurl, nbiif)
577 //rlist := make(map[string]string)
578 xapp.Logger.Info("Reading SDL for any routes")
579 rlist, sdlerr := xapp.SdlStorage.Read(rtmgr.RTMGR_SDL_NS, "routes")
582 xapp.Logger.Info("Value is %s", rlist["routes"])
583 if rlist["routes"] != nil {
584 formstring := fmt.Sprintf("%s", rlist["routes"])
585 xapp.Logger.Info("Value of formed string = %s", formstring)
586 newstring := strings.Split(formstring, " ")
587 for i, _ := range newstring {
588 xapp.Logger.Info("in Loop Value of formed string = %s", newstring)
589 rtmgr.DynamicRouteList = append(rtmgr.DynamicRouteList, newstring[i])
599 func (r *HttpRestful) Initialize(xmurl string, nbiif string, fileName string, configfile string, e2murl string,
600 sdlEngine sdl.Engine, rpeEngine rpe.Engine, m *sync.Mutex) error {
601 err := r.RetrieveStartupData(xmurl, nbiif, fileName, configfile, e2murl, sdlEngine)
603 xapp.Logger.Error("Exiting as nbi failed to get the initial startup data from the xapp manager: " + err.Error())
610 func (r *HttpRestful) Terminate() error {
614 func addSubscription(subs *rtmgr.SubscriptionList, xappSubData *models.XappSubscriptionData) bool {
615 xapp.Logger.Debug("Adding the subscription into the subscriptions list")
617 sub := rtmgr.Subscription{SubID: *xappSubData.SubscriptionID, Fqdn: *xappSubData.Address, Port: *xappSubData.Port}
618 for _, elem := range *subs {
620 xapp.Logger.Warn("rtmgr.addSubscription: Subscription already present: %v", elem)
625 *subs = append(*subs, sub)
630 func delSubscription(subs *rtmgr.SubscriptionList, xappSubData *models.XappSubscriptionData) bool {
631 xapp.Logger.Debug("Deleteing the subscription from the subscriptions list")
633 sub := rtmgr.Subscription{SubID: *xappSubData.SubscriptionID, Fqdn: *xappSubData.Address, Port: *xappSubData.Port}
634 for i, elem := range *subs {
637 // Since the order of the list is not important, we are swapping the last element
638 // with the matching element and replacing the list with list(n-1) elements.
639 (*subs)[len(*subs)-1], (*subs)[i] = (*subs)[i], (*subs)[len(*subs)-1]
640 *subs = (*subs)[:len(*subs)-1]
644 if present == false {
645 xapp.Logger.Warn("rtmgr.delSubscription: Subscription = %v, not present in the existing subscriptions", xappSubData)
650 func updateSubscription(data *rtmgr.XappList) {
652 var subdata models.XappSubscriptionData
654 var matchingsubid, deletecount uint8
655 id = int32(data.SubscriptionID)
656 subdata.SubscriptionID = &id
657 for _, subs := range rtmgr.Subs {
658 if int32(data.SubscriptionID) == subs.SubID {
663 for deletecount < matchingsubid {
664 for _, subs := range rtmgr.Subs {
665 if int32(data.SubscriptionID) == subs.SubID {
666 subdata.SubscriptionID = &subs.SubID
667 subdata.Address = &subs.Fqdn
668 subdata.Port = &subs.Port
669 xapp.Logger.Debug("Deletion Subscription List has %v", subdata)
670 delSubscription(&rtmgr.Subs, &subdata)
677 for _, items := range data.FqdnList {
678 subdata.Address = items.Address
679 subdata.Port = items.Port
680 xapp.Logger.Debug("Adding Subscription List has %v", subdata)
681 addSubscription(&rtmgr.Subs, &subdata)
686 func PopulateSubscription(sub_list xfmodel.SubscriptionList) {
687 for _, sub_row := range sub_list {
688 var subdata models.XappSubscriptionData
689 id := int32(sub_row.SubscriptionID)
690 subdata.SubscriptionID = &id
691 for _, ep := range sub_row.ClientEndpoint {
692 stringSlice := strings.Split(ep, ":")
693 subdata.Address = &stringSlice[0]
694 intportval, _ := strconv.Atoi(stringSlice[1])
695 value := uint16(intportval)
696 subdata.Port = &value
697 xapp.Logger.Debug("Adding Subscription List has Address :%v, port :%v, SubscriptionID :%v ", subdata.Address, subdata.Address, subdata.SubscriptionID)
698 addSubscription(&rtmgr.Subs, &subdata)
703 func Adddelrmrroute(routelist models.Routelist, rtflag bool) error {
704 xapp.Logger.Info("Updating rmrroute with Route list: %v,flag: %v", routelist, rtflag)
705 for _, rlist := range routelist {
708 if rlist.SubscriptionID == 0 {
711 subid = rlist.SubscriptionID
713 if rlist.SenderEndPoint == "" && rlist.SubscriptionID != 0 {
714 data = fmt.Sprintf("mse|%d|%d|%s\n", *rlist.MessageType, rlist.SubscriptionID, *rlist.TargetEndPoint)
715 } else if rlist.SenderEndPoint == "" && rlist.SubscriptionID == 0 {
716 data = fmt.Sprintf("mse|%d|-1|%s\n", *rlist.MessageType, *rlist.TargetEndPoint)
718 data = fmt.Sprintf("mse|%d,%s|%d|%s\n", *rlist.MessageType, rlist.SenderEndPoint, subid, *rlist.TargetEndPoint)
720 err := checkrepeatedroute(data)
724 xapp.Logger.Info("Given route %s is a duplicate", data)
726 rtmgr.DynamicRouteList = append(rtmgr.DynamicRouteList, data)
727 routearray := strings.Join(rtmgr.DynamicRouteList, " ")
728 xapp.SdlStorage.Store(rtmgr.RTMGR_SDL_NS, "routes", routearray)
731 xapp.Logger.Info("Successfully deleted route: %s", data)
732 routearray := strings.Join(rtmgr.DynamicRouteList, " ")
733 xapp.SdlStorage.Store(rtmgr.RTMGR_SDL_NS, "routes", routearray)
735 xapp.Logger.Info("No such route: %s", data)
736 return errors.New("No such route: " + data)
742 return sendRoutesToAll()
745 func checkrepeatedroute(data string) bool {
746 for i := 0; i < len(rtmgr.DynamicRouteList); i++ {
747 if rtmgr.DynamicRouteList[i] == data {
748 rtmgr.DynamicRouteList[i] = rtmgr.DynamicRouteList[len(rtmgr.DynamicRouteList)-1]
749 rtmgr.DynamicRouteList[len(rtmgr.DynamicRouteList)-1] = ""
750 rtmgr.DynamicRouteList = rtmgr.DynamicRouteList[:len(rtmgr.DynamicRouteList)-1]