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")
131 err := validateXappCallbackData(data)
133 xapp.Logger.Warn("XApp callback data validation failed: " + err.Error())
136 appdata, err := recvXappCallbackData(data)
138 xapp.Logger.Error("cannot get data from rest api dute to: " + err.Error())
139 } else if appdata != nil {
140 xapp.Logger.Debug("Fetching all xApps deployed in xApp Manager through GET operation.")
141 alldata, err1 := httpGetXApps(xapp.Config.GetString("xmurl"))
142 if alldata != nil && err1 == nil {
144 sdlEngine.WriteXApps(xapp.Config.GetString("rtfile"), alldata)
146 return sendRoutesToAll()
154 func validateXappSubscriptionData(data *models.XappSubscriptionData) error {
155 var err = fmt.Errorf("XApp instance not found: %v:%v", *data.Address, *data.Port)
156 for _, ep := range rtmgr.Eps {
157 if ep.Ip == *data.Address && ep.Port == *data.Port {
165 func validateE2tData(data *models.E2tData) error {
167 e2taddress_key := *data.E2TAddress
168 if e2taddress_key == "" {
169 return fmt.Errorf("E2TAddress is empty!!!")
171 stringSlice := strings.Split(e2taddress_key, ":")
172 if len(stringSlice) == 1 {
173 return fmt.Errorf("E2T E2TAddress is not a proper format like ip:port, %v", e2taddress_key)
176 _, err := net.LookupIP(stringSlice[0])
178 return fmt.Errorf("E2T E2TAddress DNS look up failed, E2TAddress: %v", stringSlice[0])
181 if checkValidaE2TAddress(e2taddress_key) {
182 return fmt.Errorf("E2TAddress already exist!!!, E2TAddress: %v", e2taddress_key)
188 func validateDeleteE2tData(data *models.E2tDeleteData) error {
190 if *data.E2TAddress == "" {
191 return fmt.Errorf("E2TAddress is empty!!!")
194 for _, element := range data.RanAssocList {
195 e2taddress_key := *element.E2TAddress
196 stringSlice := strings.Split(e2taddress_key, ":")
198 if len(stringSlice) == 1 {
199 return fmt.Errorf("E2T Delete - RanAssocList E2TAddress is not a proper format like ip:port, %v", e2taddress_key)
202 if !checkValidaE2TAddress(e2taddress_key) {
203 return fmt.Errorf("E2TAddress doesn't exist!!!, E2TAddress: %v", e2taddress_key)
210 func checkValidaE2TAddress(e2taddress string) bool {
212 _, exist := rtmgr.Eps[e2taddress]
217 func provideXappSubscriptionHandleImpl(data *models.XappSubscriptionData) error {
218 xapp.Logger.Debug("Invoked provideXappSubscriptionHandleImpl")
219 err := validateXappSubscriptionData(data)
221 xapp.Logger.Error(err.Error())
224 xapp.Logger.Debug("received XApp subscription data")
225 addSubscription(&rtmgr.Subs, data)
226 xapp.Logger.Debug("Endpoints: %v", rtmgr.Eps)
227 return sendRoutesToAll()
230 func subscriptionExists(data *models.XappSubscriptionData) bool {
232 sub := rtmgr.Subscription{SubID: *data.SubscriptionID, Fqdn: *data.Address, Port: *data.Port}
233 for _, elem := range rtmgr.Subs {
242 func deleteXappSubscriptionHandleImpl(data *models.XappSubscriptionData) error {
243 xapp.Logger.Debug("Invoked deleteXappSubscriptionHandleImpl")
244 err := validateXappSubscriptionData(data)
246 xapp.Logger.Error(err.Error())
250 if !subscriptionExists(data) {
251 xapp.Logger.Warn("subscription not found: %d", *data.SubscriptionID)
252 err := fmt.Errorf("subscription not found: %d", *data.SubscriptionID)
256 xapp.Logger.Debug("received XApp subscription delete data")
257 delSubscription(&rtmgr.Subs, data)
258 return sendRoutesToAll()
262 func updateXappSubscriptionHandleImpl(data *models.XappList, subid uint16) error {
263 xapp.Logger.Debug("Invoked updateXappSubscriptionHandleImpl")
265 var fqdnlist []rtmgr.FqDn
266 for _, item := range *data {
267 fqdnlist = append(fqdnlist, rtmgr.FqDn(*item))
269 xapplist := rtmgr.XappList{SubscriptionID: subid, FqdnList: fqdnlist}
270 var subdata models.XappSubscriptionData
273 subdata.SubscriptionID = &id
274 for _, items := range fqdnlist {
275 subdata.Address = items.Address
276 subdata.Port = items.Port
277 err := validateXappSubscriptionData(&subdata)
279 xapp.Logger.Error(err.Error())
283 xapp.Logger.Debug("received XApp subscription Merge data")
284 updateSubscription(&xapplist)
285 return sendRoutesToAll()
288 func createNewE2tHandleHandlerImpl(data *models.E2tData) error {
289 xapp.Logger.Debug("Invoked createNewE2tHandleHandlerImpl")
290 err := validateE2tData(data)
292 xapp.Logger.Error(err.Error())
296 e2data, meiddata, _ := recvNewE2Tdata(data)
297 xapp.Logger.Debug("received create New E2T data")
299 sdlEngine.WriteNewE2TInstance(xapp.Config.GetString("rtfile"), e2data, meiddata)
301 return sendRoutesToAll()
305 func validateE2TAddressRANListData(assRanE2tData models.RanE2tMap) error {
307 xapp.Logger.Debug("Invoked.validateE2TAddressRANListData : %v", assRanE2tData)
309 for _, element := range assRanE2tData {
310 if *element.E2TAddress == "" {
311 return fmt.Errorf("E2T Instance - E2TAddress is empty!!!")
314 e2taddress_key := *element.E2TAddress
315 if !checkValidaE2TAddress(e2taddress_key) {
316 return fmt.Errorf("E2TAddress doesn't exist!!!, E2TAddress: %v", e2taddress_key)
323 func associateRanToE2THandlerImpl(data models.RanE2tMap) error {
324 xapp.Logger.Debug("Invoked associateRanToE2THandlerImpl")
325 err := validateE2TAddressRANListData(data)
327 xapp.Logger.Warn(" Association of RAN to E2T Instance data validation failed: " + err.Error())
330 xapp.Logger.Debug("received associate RAN list to E2T instance mapping from E2 Manager")
332 sdlEngine.WriteAssRANToE2TInstance(xapp.Config.GetString("rtfile"), data)
334 return sendRoutesToAll()
338 func disassociateRanToE2THandlerImpl(data models.RanE2tMap) error {
339 xapp.Logger.Debug("Invoked disassociateRanToE2THandlerImpl")
340 err := validateE2TAddressRANListData(data)
342 xapp.Logger.Warn(" Disassociation of RAN List from E2T Instance data validation failed: " + err.Error())
345 xapp.Logger.Debug("received disassociate RANs from E2T instance")
347 sdlEngine.WriteDisAssRANFromE2TInstance(xapp.Config.GetString("rtfile"), data)
349 return sendRoutesToAll()
353 func deleteE2tHandleHandlerImpl(data *models.E2tDeleteData) error {
354 xapp.Logger.Debug("Invoked deleteE2tHandleHandlerImpl")
356 err := validateDeleteE2tData(data)
358 xapp.Logger.Error(err.Error())
362 sdlEngine.WriteDeleteE2TInstance(xapp.Config.GetString("rtfile"), data)
364 return sendRoutesToAll()
368 func dumpDebugData() (models.Debuginfo, error) {
369 var response models.Debuginfo
370 sdlEngine, _ := sdl.GetSdl("file")
371 rpeEngine, _ := rpe.GetRpe("rmrpush")
372 data, err := sdlEngine.ReadAll(xapp.Config.GetString("rtfile"))
373 if err != nil || data == nil {
374 xapp.Logger.Error("Cannot get data from sdl interface due to: " + err.Error())
377 response.RouteTable = *rpeEngine.GeneratePolicies(rtmgr.Eps, data)
379 prettyJSON, err := json.MarshalIndent(data, "", "")
380 response.RouteConfigs = string(prettyJSON)
385 func launchRest(nbiif *string){
386 swaggerSpec, err := loads.Embedded(restapi.SwaggerJSON, restapi.FlatSwaggerJSON)
389 xapp.Logger.Error(err.Error())
392 nbiUrl, err := url.Parse(*nbiif)
394 xapp.Logger.Error(err.Error())
397 api := operations.NewRoutingManagerAPI(swaggerSpec)
398 server := restapi.NewServer(api)
399 defer server.Shutdown()
401 server.Port, err = strconv.Atoi(nbiUrl.Port())
403 xapp.Logger.Error("Invalid NBI RestAPI port")
406 server.Host = "0.0.0.0"
408 api.HandleProvideXappHandleHandler = handle.ProvideXappHandleHandlerFunc(
409 func(params handle.ProvideXappHandleParams) middleware.Responder {
410 xapp.Logger.Info("Data received on Http interface")
411 err := provideXappHandleHandlerImpl(params.XappCallbackData)
413 xapp.Logger.Error("Invalid XApp callback data: " + err.Error())
414 return handle.NewProvideXappHandleBadRequest()
416 return handle.NewGetHandlesOK()
419 api.HandleProvideXappSubscriptionHandleHandler = handle.ProvideXappSubscriptionHandleHandlerFunc(
420 func(params handle.ProvideXappSubscriptionHandleParams) middleware.Responder {
421 err := provideXappSubscriptionHandleImpl(params.XappSubscriptionData)
423 return handle.NewProvideXappSubscriptionHandleBadRequest()
425 return handle.NewGetHandlesOK()
428 api.HandleDeleteXappSubscriptionHandleHandler = handle.DeleteXappSubscriptionHandleHandlerFunc(
429 func(params handle.DeleteXappSubscriptionHandleParams) middleware.Responder {
430 err := deleteXappSubscriptionHandleImpl(params.XappSubscriptionData)
432 return handle.NewDeleteXappSubscriptionHandleNoContent()
434 return handle.NewGetHandlesOK()
437 api.HandleUpdateXappSubscriptionHandleHandler = handle.UpdateXappSubscriptionHandleHandlerFunc(
438 func(params handle.UpdateXappSubscriptionHandleParams) middleware.Responder {
439 err := updateXappSubscriptionHandleImpl(¶ms.XappList, params.SubscriptionID)
441 return handle.NewUpdateXappSubscriptionHandleBadRequest()
443 return handle.NewUpdateXappSubscriptionHandleCreated()
446 api.HandleCreateNewE2tHandleHandler = handle.CreateNewE2tHandleHandlerFunc(
447 func(params handle.CreateNewE2tHandleParams) middleware.Responder {
448 err := createNewE2tHandleHandlerImpl(params.E2tData)
450 return handle.NewCreateNewE2tHandleBadRequest()
452 return handle.NewCreateNewE2tHandleCreated()
456 api.HandleAssociateRanToE2tHandleHandler = handle.AssociateRanToE2tHandleHandlerFunc(
457 func(params handle.AssociateRanToE2tHandleParams) middleware.Responder {
458 err := associateRanToE2THandlerImpl(params.RanE2tList)
460 return handle.NewAssociateRanToE2tHandleBadRequest()
462 return handle.NewAssociateRanToE2tHandleCreated()
466 api.HandleDissociateRanHandler = handle.DissociateRanHandlerFunc(
467 func(params handle.DissociateRanParams) middleware.Responder {
468 err := disassociateRanToE2THandlerImpl(params.DissociateList)
470 return handle.NewDissociateRanBadRequest()
472 return handle.NewDissociateRanCreated()
476 api.HandleDeleteE2tHandleHandler = handle.DeleteE2tHandleHandlerFunc(
477 func(params handle.DeleteE2tHandleParams) middleware.Responder {
478 err := deleteE2tHandleHandlerImpl(params.E2tData)
480 return handle.NewDeleteE2tHandleBadRequest()
482 return handle.NewDeleteE2tHandleCreated()
485 api.DebugGetDebuginfoHandler = debug.GetDebuginfoHandlerFunc(
486 func(params debug.GetDebuginfoParams) middleware.Responder {
487 response, err := dumpDebugData()
489 return debug.NewGetDebuginfoCreated()
491 return debug.NewGetDebuginfoOK().WithPayload(&response)
494 // start to serve API
495 xapp.Logger.Info("Starting the HTTP Rest service")
496 if err := server.Serve(); err != nil {
497 xapp.Logger.Error(err.Error())
501 func httpGetXApps(xmurl string) (*[]rtmgr.XApp, error) {
502 xapp.Logger.Info("Invoked httprestful.httpGetXApps: " + xmurl)
503 r, err := myClient.Get(xmurl)
509 if r.StatusCode == 200 {
510 xapp.Logger.Debug("http client raw response: %v", r)
511 var xapps []rtmgr.XApp
512 err = json.NewDecoder(r.Body).Decode(&xapps)
514 xapp.Logger.Warn("Json decode failed: " + err.Error())
516 xapp.Logger.Info("HTTP GET: OK")
517 xapp.Logger.Debug("httprestful.httpGetXApps returns: %v", xapps)
520 xapp.Logger.Warn("httprestful got an unexpected http status code: %v", r.StatusCode)
524 func httpGetE2TList(e2murl string) (*[]rtmgr.E2tIdentity, error) {
525 xapp.Logger.Info("Invoked httprestful.httpGetE2TList: " + e2murl)
526 r, err := myClient.Get(e2murl)
532 if r.StatusCode == 200 {
533 xapp.Logger.Debug("http client raw response: %v", r)
534 var E2Tlist []rtmgr.E2tIdentity
535 err = json.NewDecoder(r.Body).Decode(&E2Tlist)
537 xapp.Logger.Warn("Json decode failed: " + err.Error())
539 xapp.Logger.Info("HTTP GET: OK")
540 xapp.Logger.Debug("httprestful.httpGetXApps returns: %v", E2Tlist)
543 xapp.Logger.Warn("httprestful got an unexpected http status code: %v", r.StatusCode)
547 func PopulateE2TMap(e2tDataList *[]rtmgr.E2tIdentity, e2ts map[string]rtmgr.E2TInstance, meids []string) {
548 xapp.Logger.Info("Invoked httprestful.PopulateE2TMap ")
550 for _, e2tData := range *e2tDataList {
553 e2tinst := rtmgr.E2TInstance{
554 Ranlist: make([]string, len(e2tData.Rannames)),
557 e2tinst.Fqdn = e2tData.E2taddress
558 e2tinst.Name = "E2TERMINST"
559 copy(e2tinst.Ranlist, e2tData.Rannames)
561 if len(e2tData.Rannames) > 0 {
563 for _, meid := range e2tData.Rannames {
566 str += "mme_ar|" + e2tData.E2taddress + "|" + strings.TrimSuffix(meidar, " ")
569 e2ts[e2tinst.Fqdn] = e2tinst
570 meids = append(meids, str)
574 func retrieveStartupData(xmurl string, nbiif string, fileName string, configfile string, e2murl string, sdlEngine sdl.Engine) error {
575 xapp.Logger.Info("Invoked retrieveStartupData ")
579 var xappData *[]rtmgr.XApp
580 xappData = new([]rtmgr.XApp)
581 xapp.Logger.Info("Trying to fetch XApps data from XAPP manager")
582 for i := 1; i <= maxRetries; i++ {
583 time.Sleep(2 * time.Second)
586 xappData, err = httpGetXApps(xmurl)
587 if xappData != nil && err == nil {
589 } else if err == nil {
590 readErr = errors.New("unexpected HTTP status code")
592 xapp.Logger.Warn("cannot get xapp data due to: " + err.Error())
602 e2ts := make(map[string]rtmgr.E2TInstance)
603 xapp.Logger.Info("Trying to fetch E2T data from E2manager")
604 for i := 1; i <= maxRetries; i++ {
607 e2tDataList, err := httpGetE2TList(e2murl)
608 if e2tDataList != nil && err == nil {
609 PopulateE2TMap(e2tDataList, e2ts, meids[:])
611 } else if err == nil {
612 readErr = errors.New("unexpected HTTP status code")
614 xapp.Logger.Warn("cannot get E2T data from E2M due to: " + err.Error())
617 time.Sleep(2 * time.Second)
624 pcData, confErr := rtmgr.GetPlatformComponents(configfile)
626 xapp.Logger.Error(confErr.Error())
629 xapp.Logger.Info("Recieved intial xapp data, E2T data and platform data, writing into SDL.")
630 // Combine the xapps data and platform data before writing to the SDL
631 ricData := &rtmgr.RicComponents{XApps: *xappData, Pcs: *pcData, E2Ts: e2ts, MeidMap: meids}
632 writeErr := sdlEngine.WriteAll(fileName, ricData)
634 xapp.Logger.Error(writeErr.Error())
637 xapp.Logger.Info("Trying to fetch Subscriptions data from Subscription manager")
638 for i := 1; i <= maxRetries; i++ {
640 sub_list, err := xapp.Subscription.QuerySubscriptions()
642 if sub_list != nil && err == nil {
643 PopulateSubscription(sub_list)
647 xapp.Logger.Warn("cannot get xapp data due to: " + readErr.Error())
649 time.Sleep(2 * time.Second)
656 // post subscription req to appmgr
657 readErr = PostSubReq(xmurl, nbiif)
665 func (r *HttpRestful) Initialize(xmurl string, nbiif string, fileName string, configfile string, e2murl string,
666 sdlEngine sdl.Engine, rpeEngine rpe.Engine, m *sync.Mutex) error {
667 err := r.RetrieveStartupData(xmurl, nbiif, fileName, configfile, e2murl, sdlEngine)
669 xapp.Logger.Error("Exiting as nbi failed to get the initial startup data from the xapp manager: " + err.Error())
679 func (r *HttpRestful) Terminate() error {
683 func addSubscription(subs *rtmgr.SubscriptionList, xappSubData *models.XappSubscriptionData) bool {
684 xapp.Logger.Debug("Adding the subscription into the subscriptions list")
686 sub := rtmgr.Subscription{SubID: *xappSubData.SubscriptionID, Fqdn: *xappSubData.Address, Port: *xappSubData.Port}
687 for _, elem := range *subs {
689 xapp.Logger.Warn("rtmgr.addSubscription: Subscription already present: %v", elem)
694 *subs = append(*subs, sub)
699 func delSubscription(subs *rtmgr.SubscriptionList, xappSubData *models.XappSubscriptionData) bool {
700 xapp.Logger.Debug("Deleteing the subscription from the subscriptions list")
702 sub := rtmgr.Subscription{SubID: *xappSubData.SubscriptionID, Fqdn: *xappSubData.Address, Port: *xappSubData.Port}
703 for i, elem := range *subs {
706 // Since the order of the list is not important, we are swapping the last element
707 // with the matching element and replacing the list with list(n-1) elements.
708 (*subs)[len(*subs)-1], (*subs)[i] = (*subs)[i], (*subs)[len(*subs)-1]
709 *subs = (*subs)[:len(*subs)-1]
713 if present == false {
714 xapp.Logger.Warn("rtmgr.delSubscription: Subscription = %v, not present in the existing subscriptions", xappSubData)
719 func updateSubscription(data *rtmgr.XappList) {
721 var subdata models.XappSubscriptionData
723 var matchingsubid, deletecount uint8
724 id = int32(data.SubscriptionID)
725 subdata.SubscriptionID = &id
726 for _, subs := range rtmgr.Subs {
727 if int32(data.SubscriptionID) == subs.SubID {
732 for deletecount < matchingsubid {
733 for _, subs := range rtmgr.Subs {
734 if int32(data.SubscriptionID) == subs.SubID {
735 subdata.SubscriptionID = &subs.SubID
736 subdata.Address = &subs.Fqdn
737 subdata.Port = &subs.Port
738 xapp.Logger.Debug("Deletion Subscription List has %v", subdata)
739 delSubscription(&rtmgr.Subs, &subdata)
746 for _, items := range data.FqdnList {
747 subdata.Address = items.Address
748 subdata.Port = items.Port
749 xapp.Logger.Debug("Adding Subscription List has %v", subdata)
750 addSubscription(&rtmgr.Subs, &subdata)
755 func PopulateSubscription(sub_list xfmodel.SubscriptionList) {
756 for _, sub_row := range sub_list {
757 var subdata models.XappSubscriptionData
758 id := int32(sub_row.SubscriptionID)
759 subdata.SubscriptionID = &id
760 for _, ep := range sub_row.Endpoint {
762 stringSlice := strings.Split(ep, ":")
763 subdata.Address = &stringSlice[0]
764 intportval, _ := strconv.Atoi(stringSlice[1])
765 value := uint16(intportval)
766 subdata.Port = &value
767 xapp.Logger.Debug("Adding Subscription List has Address :%v, port :%v, SubscriptionID :%v ", subdata.Address, subdata.Address, subdata.SubscriptionID)
768 addSubscription(&rtmgr.Subs, &subdata)