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 "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
39 "github.com/go-openapi/loads"
40 "github.com/go-openapi/runtime/middleware"
44 "routing-manager/pkg/models"
45 "routing-manager/pkg/restapi"
46 "routing-manager/pkg/restapi/operations"
47 "routing-manager/pkg/restapi/operations/handle"
48 "routing-manager/pkg/rpe"
49 "routing-manager/pkg/rtmgr"
50 "routing-manager/pkg/sdl"
57 //var myClient = &http.Client{Timeout: 1 * time.Second}
59 type HttpRestful struct {
61 LaunchRest LaunchRestHandler
62 RecvXappCallbackData RecvXappCallbackDataHandler
63 RecvNewE2Tdata RecvNewE2TdataHandler
64 ProvideXappHandleHandlerImpl ProvideXappHandleHandlerImpl
65 RetrieveStartupData RetrieveStartupDataHandler
68 func NewHttpRestful() *HttpRestful {
69 instance := new(HttpRestful)
70 instance.LaunchRest = launchRest
71 instance.RecvXappCallbackData = recvXappCallbackData
72 instance.RecvNewE2Tdata = recvNewE2Tdata
73 instance.ProvideXappHandleHandlerImpl = provideXappHandleHandlerImpl
74 instance.RetrieveStartupData = retrieveStartupData
78 // ToDo: Use Range over channel. Read and return only the latest one.
79 func recvXappCallbackData(dataChannel <-chan *models.XappCallbackData) (*[]rtmgr.XApp, error) {
80 var xappData *models.XappCallbackData
81 // Drain the channel as we are only looking for the latest value until
82 // xapp manager sends all xapp data with every request.
83 length := len(dataChannel)
84 //xapp.Logger.Info(length)
85 for i := 0; i <= length; i++ {
86 xapp.Logger.Info("data received")
87 // If no data received from the REST, it blocks.
88 xappData = <-dataChannel
91 var xapps []rtmgr.XApp
92 err := json.Unmarshal([]byte(xappData.XApps), &xapps)
95 xapp.Logger.Info("No data")
98 xapp.Logger.Debug("Nothing received on the Http interface")
102 func recvNewE2Tdata(dataChannel <-chan *models.E2tData) (*rtmgr.E2TInstance, string, error) {
103 var e2tData *models.E2tData
105 xapp.Logger.Info("data received")
107 e2tData = <-dataChannel
111 e2tinst := rtmgr.E2TInstance{
112 Ranlist: make([]string, len(e2tData.RanNamelist)),
115 e2tinst.Fqdn = *e2tData.E2TAddress
116 e2tinst.Name = "E2TERMINST"
117 copy(e2tinst.Ranlist, e2tData.RanNamelist)
118 if len(e2tData.RanNamelist) > 0 {
120 for _, meid := range e2tData.RanNamelist {
123 str = "mme_ar|" + *e2tData.E2TAddress + "|" + strings.TrimSuffix(meidar, " ")
125 return &e2tinst, str, nil
128 xapp.Logger.Info("No data")
131 xapp.Logger.Debug("Nothing received on the Http interface")
135 func validateXappCallbackData(callbackData *models.XappCallbackData) error {
136 if len(callbackData.XApps) == 0 {
137 return fmt.Errorf("invalid Data field: \"%s\"", callbackData.XApps)
139 var xapps []rtmgr.XApp
140 err := json.Unmarshal([]byte(callbackData.XApps), &xapps)
142 return fmt.Errorf("unmarshal failed: \"%s\"", err.Error())
147 func provideXappHandleHandlerImpl(datach chan<- *models.XappCallbackData, data *models.XappCallbackData) error {
149 xapp.Logger.Debug("Received callback data")
151 err := validateXappCallbackData(data)
153 xapp.Logger.Warn("XApp callback data validation failed: " + err.Error())
161 func validateXappSubscriptionData(data *models.XappSubscriptionData) error {
162 var err = fmt.Errorf("XApp instance not found: %v:%v", *data.Address, *data.Port)
163 for _, ep := range rtmgr.Eps {
164 if ep.Ip == *data.Address && ep.Port == *data.Port {
172 func validateE2tData(data *models.E2tData) error {
174 e2taddress_key := *data.E2TAddress
175 if e2taddress_key == "" {
176 return fmt.Errorf("E2TAddress is empty!!!")
178 stringSlice := strings.Split(e2taddress_key, ":")
179 if len(stringSlice) == 1 {
180 return fmt.Errorf("E2T E2TAddress is not a proper format like ip:port, %v", e2taddress_key)
183 _, err := net.LookupIP(stringSlice[0])
185 return fmt.Errorf("E2T E2TAddress DNS look up failed, E2TAddress: %v", stringSlice[0])
188 if checkValidaE2TAddress(e2taddress_key) {
189 return fmt.Errorf("E2TAddress already exist!!!, E2TAddress: %v", e2taddress_key)
195 func validateDeleteE2tData(data *models.E2tDeleteData) error {
197 if *data.E2TAddress == "" {
198 return fmt.Errorf("E2TAddress is empty!!!")
201 for _, element := range data.RanAssocList {
202 e2taddress_key := *element.E2TAddress
203 stringSlice := strings.Split(e2taddress_key, ":")
205 if len(stringSlice) == 1 {
206 return fmt.Errorf("E2T Delete - RanAssocList E2TAddress is not a proper format like ip:port, %v", e2taddress_key)
209 if !checkValidaE2TAddress(e2taddress_key) {
210 return fmt.Errorf("E2TAddress doesn't exist!!!, E2TAddress: %v", e2taddress_key)
217 func checkValidaE2TAddress(e2taddress string) bool {
219 _, exist := rtmgr.Eps[e2taddress]
224 func provideXappSubscriptionHandleImpl(subchan chan<- *models.XappSubscriptionData,
225 data *models.XappSubscriptionData) error {
226 xapp.Logger.Debug("Invoked provideXappSubscriptionHandleImpl")
227 err := validateXappSubscriptionData(data)
229 xapp.Logger.Error(err.Error())
233 //var val = string(*data.Address + ":" + strconv.Itoa(int(*data.Port)))
234 xapp.Logger.Debug("Endpoints: %v", rtmgr.Eps)
238 func subscriptionExists(data *models.XappSubscriptionData) bool {
240 sub := rtmgr.Subscription{SubID: *data.SubscriptionID, Fqdn: *data.Address, Port: *data.Port}
241 for _, elem := range rtmgr.Subs {
250 func deleteXappSubscriptionHandleImpl(subdelchan chan<- *models.XappSubscriptionData,
251 data *models.XappSubscriptionData) error {
252 xapp.Logger.Debug("Invoked deleteXappSubscriptionHandleImpl")
253 err := validateXappSubscriptionData(data)
255 xapp.Logger.Error(err.Error())
259 if !subscriptionExists(data) {
260 xapp.Logger.Warn("subscription not found: %d", *data.SubscriptionID)
261 err := fmt.Errorf("subscription not found: %d", *data.SubscriptionID)
269 func updateXappSubscriptionHandleImpl(subupdatechan chan<- *rtmgr.XappList, data *models.XappList, subid uint16) error {
270 xapp.Logger.Debug("Invoked updateXappSubscriptionHandleImpl")
272 var fqdnlist []rtmgr.FqDn
273 for _, item := range *data {
274 fqdnlist = append(fqdnlist, rtmgr.FqDn(*item))
276 xapplist := rtmgr.XappList{SubscriptionID: subid, FqdnList: fqdnlist}
277 var subdata models.XappSubscriptionData
280 subdata.SubscriptionID = &id
281 for _, items := range fqdnlist {
282 subdata.Address = items.Address
283 subdata.Port = items.Port
284 err := validateXappSubscriptionData(&subdata)
286 xapp.Logger.Error(err.Error())
290 subupdatechan <- &xapplist
294 func createNewE2tHandleHandlerImpl(e2taddchan chan<- *models.E2tData,
295 data *models.E2tData) error {
296 xapp.Logger.Debug("Invoked createNewE2tHandleHandlerImpl")
297 err := validateE2tData(data)
299 xapp.Logger.Error(err.Error())
306 func validateE2TAddressRANListData(assRanE2tData models.RanE2tMap) error {
308 xapp.Logger.Debug("Invoked.validateE2TAddressRANListData : %v", assRanE2tData)
310 for _, element := range assRanE2tData {
311 if *element.E2TAddress == "" {
312 return fmt.Errorf("E2T Instance - E2TAddress is empty!!!")
315 e2taddress_key := *element.E2TAddress
316 if !checkValidaE2TAddress(e2taddress_key) {
317 return fmt.Errorf("E2TAddress doesn't exist!!!, E2TAddress: %v", e2taddress_key)
324 func associateRanToE2THandlerImpl(assranchan chan<- models.RanE2tMap,
325 data models.RanE2tMap) error {
326 xapp.Logger.Debug("Invoked associateRanToE2THandlerImpl")
327 err := validateE2TAddressRANListData(data)
329 xapp.Logger.Warn(" Association of RAN to E2T Instance data validation failed: " + err.Error())
336 func disassociateRanToE2THandlerImpl(disassranchan chan<- models.RanE2tMap,
337 data models.RanE2tMap) error {
338 xapp.Logger.Debug("Invoked disassociateRanToE2THandlerImpl")
339 err := validateE2TAddressRANListData(data)
341 xapp.Logger.Warn(" Disassociation of RAN List from E2T Instance data validation failed: " + err.Error())
344 disassranchan <- data
348 func deleteE2tHandleHandlerImpl(e2tdelchan chan<- *models.E2tDeleteData,
349 data *models.E2tDeleteData) error {
350 xapp.Logger.Debug("Invoked deleteE2tHandleHandlerImpl")
352 err := validateDeleteE2tData(data)
354 xapp.Logger.Error(err.Error())
362 func launchRest(nbiif *string, datach chan<- *models.XappCallbackData, subchan chan<- *models.XappSubscriptionData, subupdatechan chan<- *rtmgr.XappList,
363 subdelchan chan<- *models.XappSubscriptionData, e2taddchan chan<- *models.E2tData, assranchan chan<- models.RanE2tMap, disassranchan chan<- models.RanE2tMap, e2tdelchan chan<- *models.E2tDeleteData) {
364 swaggerSpec, err := loads.Embedded(restapi.SwaggerJSON, restapi.FlatSwaggerJSON)
367 xapp.Logger.Error(err.Error())
370 nbiUrl, err := url.Parse(*nbiif)
372 xapp.Logger.Error(err.Error())
375 api := operations.NewRoutingManagerAPI(swaggerSpec)
376 server := restapi.NewServer(api)
377 defer server.Shutdown()
379 server.Port, err = strconv.Atoi(nbiUrl.Port())
381 xapp.Logger.Error("Invalid NBI RestAPI port")
384 server.Host = "0.0.0.0"
386 api.HandleProvideXappHandleHandler = handle.ProvideXappHandleHandlerFunc(
387 func(params handle.ProvideXappHandleParams) middleware.Responder {
388 xapp.Logger.Info("Data received on Http interface")
389 err := provideXappHandleHandlerImpl(datach, params.XappCallbackData)
391 xapp.Logger.Error("Invalid XApp callback data: " + err.Error())
392 return handle.NewProvideXappHandleBadRequest()
394 return handle.NewGetHandlesOK()
397 api.HandleProvideXappSubscriptionHandleHandler = handle.ProvideXappSubscriptionHandleHandlerFunc(
398 func(params handle.ProvideXappSubscriptionHandleParams) middleware.Responder {
399 err := provideXappSubscriptionHandleImpl(subchan, params.XappSubscriptionData)
401 return handle.NewProvideXappSubscriptionHandleBadRequest()
403 //Delay the reponse as add subscription channel needs to update sdl and then sbi sends updated routes to all endpoints
404 time.Sleep(1 * time.Second)
405 return handle.NewGetHandlesOK()
408 api.HandleDeleteXappSubscriptionHandleHandler = handle.DeleteXappSubscriptionHandleHandlerFunc(
409 func(params handle.DeleteXappSubscriptionHandleParams) middleware.Responder {
410 err := deleteXappSubscriptionHandleImpl(subdelchan, params.XappSubscriptionData)
412 return handle.NewDeleteXappSubscriptionHandleNoContent()
414 //Delay the reponse as delete subscription channel needs to update sdl and then sbi sends updated routes to all endpoints
415 time.Sleep(1 * time.Second)
416 return handle.NewGetHandlesOK()
419 api.HandleUpdateXappSubscriptionHandleHandler = handle.UpdateXappSubscriptionHandleHandlerFunc(
420 func(params handle.UpdateXappSubscriptionHandleParams) middleware.Responder {
421 err := updateXappSubscriptionHandleImpl(subupdatechan, ¶ms.XappList, params.SubscriptionID)
423 return handle.NewUpdateXappSubscriptionHandleBadRequest()
425 //Delay the reponse as delete subscription channel needs to update sdl and then sbi sends updated routes to all endpoints
426 time.Sleep(1 * time.Second)
427 return handle.NewUpdateXappSubscriptionHandleCreated()
430 api.HandleCreateNewE2tHandleHandler = handle.CreateNewE2tHandleHandlerFunc(
431 func(params handle.CreateNewE2tHandleParams) middleware.Responder {
432 err := createNewE2tHandleHandlerImpl(e2taddchan, params.E2tData)
434 return handle.NewCreateNewE2tHandleBadRequest()
436 time.Sleep(1 * time.Second)
437 return handle.NewCreateNewE2tHandleCreated()
441 api.HandleAssociateRanToE2tHandleHandler = handle.AssociateRanToE2tHandleHandlerFunc(
442 func(params handle.AssociateRanToE2tHandleParams) middleware.Responder {
443 err := associateRanToE2THandlerImpl(assranchan, params.RanE2tList)
445 return handle.NewAssociateRanToE2tHandleBadRequest()
447 time.Sleep(1 * time.Second)
448 return handle.NewAssociateRanToE2tHandleCreated()
452 api.HandleDissociateRanHandler = handle.DissociateRanHandlerFunc(
453 func(params handle.DissociateRanParams) middleware.Responder {
454 err := disassociateRanToE2THandlerImpl(disassranchan, params.DissociateList)
456 return handle.NewDissociateRanBadRequest()
458 time.Sleep(1 * time.Second)
459 return handle.NewDissociateRanCreated()
463 api.HandleDeleteE2tHandleHandler = handle.DeleteE2tHandleHandlerFunc(
464 func(params handle.DeleteE2tHandleParams) middleware.Responder {
465 err := deleteE2tHandleHandlerImpl(e2tdelchan, params.E2tData)
467 return handle.NewDeleteE2tHandleBadRequest()
469 time.Sleep(1 * time.Second)
470 return handle.NewDeleteE2tHandleCreated()
473 // start to serve API
474 xapp.Logger.Info("Starting the HTTP Rest service")
475 if err := server.Serve(); err != nil {
476 xapp.Logger.Error(err.Error())
480 func httpGetXApps(xmurl string) (*[]rtmgr.XApp, error) {
481 xapp.Logger.Info("Invoked httprestful.httpGetXApps: " + xmurl)
482 r, err := myClient.Get(xmurl)
488 if r.StatusCode == 200 {
489 xapp.Logger.Debug("http client raw response: %v", r)
490 var xapps []rtmgr.XApp
491 err = json.NewDecoder(r.Body).Decode(&xapps)
493 xapp.Logger.Warn("Json decode failed: " + err.Error())
495 xapp.Logger.Info("HTTP GET: OK")
496 xapp.Logger.Debug("httprestful.httpGetXApps returns: %v", xapps)
499 xapp.Logger.Warn("httprestful got an unexpected http status code: %v", r.StatusCode)
503 func retrieveStartupData(xmurl string, nbiif string, fileName string, configfile string, sdlEngine sdl.Engine) error {
506 for i := 1; i <= maxRetries; i++ {
507 time.Sleep(2 * time.Second)
508 xappData, err := httpGetXApps(xmurl)
509 if xappData != nil && err == nil {
510 pcData, confErr := rtmgr.GetPlatformComponents(configfile)
512 xapp.Logger.Error(confErr.Error())
515 xapp.Logger.Info("Recieved intial xapp data and platform data, writing into SDL.")
516 // Combine the xapps data and platform data before writing to the SDL
517 ricData := &rtmgr.RicComponents{XApps: *xappData, Pcs: *pcData, E2Ts: make(map[string]rtmgr.E2TInstance)}
518 writeErr := sdlEngine.WriteAll(fileName, ricData)
520 xapp.Logger.Error(writeErr.Error())
522 // post subscription req to appmgr
523 readErr = PostSubReq(xmurl, nbiif)
527 } else if err == nil {
528 readErr = errors.New("unexpected HTTP status code")
530 xapp.Logger.Warn("cannot get xapp data due to: " + err.Error())
537 func (r *HttpRestful) Initialize(xmurl string, nbiif string, fileName string, configfile string,
538 sdlEngine sdl.Engine, rpeEngine rpe.Engine, triggerSBI chan<- bool, m *sync.Mutex) error {
539 err := r.RetrieveStartupData(xmurl, nbiif, fileName, configfile, sdlEngine)
541 xapp.Logger.Error("Exiting as nbi failed to get the initial startup data from the xapp manager: " + err.Error())
545 datach := make(chan *models.XappCallbackData, 10)
546 subschan := make(chan *models.XappSubscriptionData, 10)
547 subdelchan := make(chan *models.XappSubscriptionData, 10)
548 subupdatechan := make(chan *rtmgr.XappList, 10)
549 e2taddchan := make(chan *models.E2tData, 10)
550 associateranchan := make(chan models.RanE2tMap, 10)
551 disassociateranchan := make(chan models.RanE2tMap, 10)
552 e2tdelchan := make(chan *models.E2tDeleteData, 10)
553 xapp.Logger.Info("Launching Rest Http service")
555 r.LaunchRest(&nbiif, datach, subschan, subupdatechan, subdelchan, e2taddchan, associateranchan, disassociateranchan, e2tdelchan)
560 data, err := r.RecvXappCallbackData(datach)
562 xapp.Logger.Error("cannot get data from rest api dute to: " + err.Error())
563 } else if data != nil {
564 xapp.Logger.Debug("Fetching all xApps deployed in xApp Manager through GET operation.")
565 alldata, err1 := httpGetXApps(xmurl)
566 if alldata != nil && err1 == nil {
568 sdlEngine.WriteXApps(fileName, alldata)
579 xapp.Logger.Debug("received XApp subscription data")
580 addSubscription(&rtmgr.Subs, data)
588 xapp.Logger.Debug("received XApp subscription delete data")
589 delSubscription(&rtmgr.Subs, data)
596 data := <-subupdatechan
597 xapp.Logger.Debug("received XApp subscription Merge data")
598 updateSubscription(data)
606 data, meiddata, _ := r.RecvNewE2Tdata(e2taddchan)
608 xapp.Logger.Debug("received create New E2T data")
610 sdlEngine.WriteNewE2TInstance(fileName, data, meiddata)
619 data := <-associateranchan
620 xapp.Logger.Debug("received associate RAN list to E2T instance mapping from E2 Manager")
622 sdlEngine.WriteAssRANToE2TInstance(fileName, data)
631 data := <-disassociateranchan
632 xapp.Logger.Debug("received disassociate RANs from E2T instance")
634 sdlEngine.WriteDisAssRANFromE2TInstance(fileName, data)
644 xapp.Logger.Debug("received Delete E2T data")
647 sdlEngine.WriteDeleteE2TInstance(fileName, data)
657 func (r *HttpRestful) Terminate() error {
661 func addSubscription(subs *rtmgr.SubscriptionList, xappSubData *models.XappSubscriptionData) bool {
662 xapp.Logger.Debug("Adding the subscription into the subscriptions list")
664 sub := rtmgr.Subscription{SubID: *xappSubData.SubscriptionID, Fqdn: *xappSubData.Address, Port: *xappSubData.Port}
665 for _, elem := range *subs {
667 xapp.Logger.Warn("rtmgr.addSubscription: Subscription already present: %v", elem)
672 *subs = append(*subs, sub)
677 func delSubscription(subs *rtmgr.SubscriptionList, xappSubData *models.XappSubscriptionData) bool {
678 xapp.Logger.Debug("Deleteing the subscription from the subscriptions list")
680 sub := rtmgr.Subscription{SubID: *xappSubData.SubscriptionID, Fqdn: *xappSubData.Address, Port: *xappSubData.Port}
681 for i, elem := range *subs {
684 // Since the order of the list is not important, we are swapping the last element
685 // with the matching element and replacing the list with list(n-1) elements.
686 (*subs)[len(*subs)-1], (*subs)[i] = (*subs)[i], (*subs)[len(*subs)-1]
687 *subs = (*subs)[:len(*subs)-1]
691 if present == false {
692 xapp.Logger.Warn("rtmgr.delSubscription: Subscription = %v, not present in the existing subscriptions", xappSubData)
697 func updateSubscription(data *rtmgr.XappList) {
699 var subdata models.XappSubscriptionData
701 var matchingsubid, deletecount uint8
702 id = int32(data.SubscriptionID)
703 subdata.SubscriptionID = &id
704 for _, subs := range rtmgr.Subs {
705 if int32(data.SubscriptionID) == subs.SubID {
710 for deletecount < matchingsubid {
711 for _, subs := range rtmgr.Subs {
712 if int32(data.SubscriptionID) == subs.SubID {
713 subdata.SubscriptionID = &subs.SubID
714 subdata.Address = &subs.Fqdn
715 subdata.Port = &subs.Port
716 xapp.Logger.Debug("Deletion Subscription List has %v", subdata)
717 delSubscription(&rtmgr.Subs, &subdata)
724 for _, items := range data.FqdnList {
725 subdata.Address = items.Address
726 subdata.Port = items.Port
727 xapp.Logger.Debug("Adding Subscription List has %v", subdata)
728 addSubscription(&rtmgr.Subs, &subdata)