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"
43 "routing-manager/pkg/models"
44 "routing-manager/pkg/restapi"
45 "routing-manager/pkg/restapi/operations"
46 "routing-manager/pkg/restapi/operations/handle"
47 "routing-manager/pkg/rpe"
48 "routing-manager/pkg/rtmgr"
49 "routing-manager/pkg/sdl"
54 //var myClient = &http.Client{Timeout: 1 * time.Second}
56 type HttpRestful struct {
58 LaunchRest LaunchRestHandler
59 RecvXappCallbackData RecvXappCallbackDataHandler
60 RecvNewE2Tdata RecvNewE2TdataHandler
62 ProvideXappHandleHandlerImpl ProvideXappHandleHandlerImpl
63 RetrieveStartupData RetrieveStartupDataHandler
66 func NewHttpRestful() *HttpRestful {
67 instance := new(HttpRestful)
68 instance.LaunchRest = launchRest
69 instance.RecvXappCallbackData = recvXappCallbackData
70 instance.RecvNewE2Tdata = recvNewE2Tdata
71 instance.ProvideXappHandleHandlerImpl = provideXappHandleHandlerImpl
72 instance.RetrieveStartupData = retrieveStartupData
76 // ToDo: Use Range over channel. Read and return only the latest one.
77 func recvXappCallbackData(dataChannel <-chan *models.XappCallbackData) (*[]rtmgr.XApp, error) {
78 var xappData *models.XappCallbackData
79 // Drain the channel as we are only looking for the latest value until
80 // xapp manager sends all xapp data with every request.
81 length := len(dataChannel)
82 //xapp.Logger.Info(length)
83 for i := 0; i <= length; i++ {
84 xapp.Logger.Info("data received")
85 // If no data received from the REST, it blocks.
86 xappData = <-dataChannel
89 var xapps []rtmgr.XApp
90 err := json.Unmarshal([]byte(xappData.XApps), &xapps)
93 xapp.Logger.Info("No data")
96 xapp.Logger.Debug("Nothing received on the Http interface")
100 func recvNewE2Tdata(dataChannel <-chan *models.E2tData) (*rtmgr.E2TInstance, error) {
101 var e2tData *models.E2tData
102 xapp.Logger.Info("data received")
104 e2tData = <-dataChannel
107 var e2tinst rtmgr.E2TInstance
108 e2tinst.Fqdn = *e2tData.E2TAddress
109 e2tinst.Name = "E2TERMINST"
112 xapp.Logger.Info("No data")
115 xapp.Logger.Debug("Nothing received on the Http interface")
122 func validateXappCallbackData(callbackData *models.XappCallbackData) error {
123 if len(callbackData.XApps) == 0 {
124 return fmt.Errorf("invalid Data field: \"%s\"", callbackData.XApps)
126 var xapps []rtmgr.XApp
127 err := json.Unmarshal([]byte(callbackData.XApps), &xapps)
129 return fmt.Errorf("unmarshal failed: \"%s\"", err.Error())
134 func provideXappHandleHandlerImpl(datach chan<- *models.XappCallbackData, data *models.XappCallbackData) error {
136 xapp.Logger.Debug("Received callback data")
138 err := validateXappCallbackData(data)
140 xapp.Logger.Warn("XApp callback data validation failed: " + err.Error())
148 func validateXappSubscriptionData(data *models.XappSubscriptionData) error {
149 var err = fmt.Errorf("XApp instance not found: %v:%v", *data.Address, *data.Port)
150 for _, ep := range rtmgr.Eps {
151 if ep.Ip == *data.Address && ep.Port == *data.Port {
159 func validateE2tData(data *models.E2tData) error {
160 var err = fmt.Errorf("E2T E2TAddress is not proper: %v", *data.E2TAddress)
161 /* for _, ep := range rtmgr.Eps {
162 if ep.Ip == *data.Address && ep.Port == *data.Port {
168 if (*data.E2TAddress != "") {
174 func provideXappSubscriptionHandleImpl(subchan chan<- *models.XappSubscriptionData,
175 data *models.XappSubscriptionData) error {
176 xapp.Logger.Debug("Invoked provideXappSubscriptionHandleImpl")
177 err := validateXappSubscriptionData(data)
179 xapp.Logger.Error(err.Error())
183 //var val = string(*data.Address + ":" + strconv.Itoa(int(*data.Port)))
184 xapp.Logger.Debug("Endpoints: %v", rtmgr.Eps)
188 func subscriptionExists(data *models.XappSubscriptionData) bool {
190 sub := rtmgr.Subscription{SubID: *data.SubscriptionID, Fqdn: *data.Address, Port: *data.Port}
191 for _, elem := range rtmgr.Subs {
200 func deleteXappSubscriptionHandleImpl(subdelchan chan<- *models.XappSubscriptionData,
201 data *models.XappSubscriptionData) error {
202 xapp.Logger.Debug("Invoked deleteXappSubscriptionHandleImpl")
203 err := validateXappSubscriptionData(data)
205 xapp.Logger.Error(err.Error())
209 if !subscriptionExists(data) {
210 xapp.Logger.Warn("subscription not found: %d", *data.SubscriptionID)
211 err := fmt.Errorf("subscription not found: %d", *data.SubscriptionID)
219 func createNewE2tHandleHandlerImpl(e2taddchan chan<- *models.E2tData,
220 data *models.E2tData) error {
221 xapp.Logger.Debug("Invoked createNewE2tHandleHandlerImpl")
222 err := validateE2tData(data)
224 xapp.Logger.Error(err.Error())
232 func launchRest(nbiif *string, datach chan<- *models.XappCallbackData, subchan chan<- *models.XappSubscriptionData,
233 subdelchan chan<- *models.XappSubscriptionData, e2taddchan chan<- *models.E2tData) {
234 swaggerSpec, err := loads.Embedded(restapi.SwaggerJSON, restapi.FlatSwaggerJSON)
237 xapp.Logger.Error(err.Error())
240 nbiUrl, err := url.Parse(*nbiif)
242 xapp.Logger.Error(err.Error())
245 api := operations.NewRoutingManagerAPI(swaggerSpec)
246 server := restapi.NewServer(api)
247 defer server.Shutdown()
249 server.Port, err = strconv.Atoi(nbiUrl.Port())
251 xapp.Logger.Error("Invalid NBI RestAPI port")
254 server.Host = "0.0.0.0"
256 api.HandleProvideXappHandleHandler = handle.ProvideXappHandleHandlerFunc(
257 func(params handle.ProvideXappHandleParams) middleware.Responder {
258 xapp.Logger.Info("Data received on Http interface")
259 err := provideXappHandleHandlerImpl(datach, params.XappCallbackData)
261 xapp.Logger.Error("Invalid XApp callback data: " + err.Error())
262 return handle.NewProvideXappHandleBadRequest()
264 return handle.NewGetHandlesOK()
267 api.HandleProvideXappSubscriptionHandleHandler = handle.ProvideXappSubscriptionHandleHandlerFunc(
268 func(params handle.ProvideXappSubscriptionHandleParams) middleware.Responder {
269 err := provideXappSubscriptionHandleImpl(subchan, params.XappSubscriptionData)
271 return handle.NewProvideXappSubscriptionHandleBadRequest()
273 //Delay the reponse as add subscription channel needs to update sdl and then sbi sends updated routes to all endpoints
274 time.Sleep(1 * time.Second)
275 return handle.NewGetHandlesOK()
278 api.HandleDeleteXappSubscriptionHandleHandler = handle.DeleteXappSubscriptionHandleHandlerFunc(
279 func(params handle.DeleteXappSubscriptionHandleParams) middleware.Responder {
280 err := deleteXappSubscriptionHandleImpl(subdelchan, params.XappSubscriptionData)
282 return handle.NewDeleteXappSubscriptionHandleNoContent()
284 //Delay the reponse as delete subscription channel needs to update sdl and then sbi sends updated routes to all endpoints
285 time.Sleep(1 * time.Second)
286 return handle.NewGetHandlesOK()
289 api.HandleCreateNewE2tHandleHandler = handle.CreateNewE2tHandleHandlerFunc(
290 func(params handle.CreateNewE2tHandleParams) middleware.Responder {
291 err := createNewE2tHandleHandlerImpl(e2taddchan, params.E2tData)
293 return handle.NewCreateNewE2tHandleBadRequest()
295 time.Sleep(1 * time.Second)
296 return handle.NewCreateNewE2tHandleCreated()
300 // start to serve API
301 xapp.Logger.Info("Starting the HTTP Rest service")
302 if err := server.Serve(); err != nil {
303 xapp.Logger.Error(err.Error())
307 func httpGetXApps(xmurl string) (*[]rtmgr.XApp, error) {
308 xapp.Logger.Info("Invoked httprestful.httpGetXApps: " + xmurl)
309 r, err := myClient.Get(xmurl)
315 if r.StatusCode == 200 {
316 xapp.Logger.Debug("http client raw response: %v", r)
317 var xapps []rtmgr.XApp
318 err = json.NewDecoder(r.Body).Decode(&xapps)
320 xapp.Logger.Warn("Json decode failed: " + err.Error())
322 xapp.Logger.Info("HTTP GET: OK")
323 xapp.Logger.Debug("httprestful.httpGetXApps returns: %v", xapps)
326 xapp.Logger.Warn("httprestful got an unexpected http status code: %v", r.StatusCode)
330 func retrieveStartupData(xmurl string, nbiif string, fileName string, configfile string, sdlEngine sdl.Engine) error {
333 for i := 1; i <= maxRetries; i++ {
334 time.Sleep(2 * time.Second)
335 xappData, err := httpGetXApps(xmurl)
336 if xappData != nil && err == nil {
337 pcData, confErr := rtmgr.GetPlatformComponents(configfile)
339 xapp.Logger.Error(confErr.Error())
342 xapp.Logger.Info("Recieved intial xapp data and platform data, writing into SDL.")
343 // Combine the xapps data and platform data before writing to the SDL
344 ricData := &rtmgr.RicComponents{XApps: *xappData, Pcs: *pcData, E2Ts: make(map[string]rtmgr.E2TInstance)}
345 writeErr := sdlEngine.WriteAll(fileName, ricData)
347 xapp.Logger.Error(writeErr.Error())
349 // post subscription req to appmgr
350 readErr = PostSubReq(xmurl, nbiif)
354 } else if err == nil {
355 readErr = errors.New("unexpected HTTP status code")
357 xapp.Logger.Warn("cannot get xapp data due to: " + err.Error())
364 func (r *HttpRestful) Initialize(xmurl string, nbiif string, fileName string, configfile string,
365 sdlEngine sdl.Engine, rpeEngine rpe.Engine, triggerSBI chan<- bool) error {
366 err := r.RetrieveStartupData(xmurl, nbiif, fileName, configfile, sdlEngine)
368 xapp.Logger.Error("Exiting as nbi failed to get the initial startup data from the xapp manager: " + err.Error())
372 datach := make(chan *models.XappCallbackData, 10)
373 subschan := make(chan *models.XappSubscriptionData, 10)
374 subdelchan := make(chan *models.XappSubscriptionData, 10)
375 e2taddchan := make(chan *models.E2tData, 10)
376 xapp.Logger.Info("Launching Rest Http service")
378 r.LaunchRest(&nbiif, datach, subschan, subdelchan, e2taddchan)
383 data, err := r.RecvXappCallbackData(datach)
385 xapp.Logger.Error("cannot get data from rest api dute to: " + err.Error())
386 } else if data != nil {
387 xapp.Logger.Debug("Fetching all xApps deployed in xApp Manager through GET operation.")
388 alldata, err1 := httpGetXApps(xmurl)
389 if alldata != nil && err1 == nil {
390 sdlEngine.WriteXApps(fileName, alldata)
400 xapp.Logger.Debug("received XApp subscription data")
401 addSubscription(&rtmgr.Subs, data)
409 xapp.Logger.Debug("received XApp subscription delete data")
410 delSubscription(&rtmgr.Subs, data)
417 xapp.Logger.Debug("received create New E2T data")
419 data, err := r.RecvNewE2Tdata(e2taddchan)
421 xapp.Logger.Error("cannot get data from rest api dute to: " + err.Error())
422 } else if data != nil {
423 sdlEngine.WriteNewE2TInstance(fileName, data)
432 func (r *HttpRestful) Terminate() error {
436 func addSubscription(subs *rtmgr.SubscriptionList, xappSubData *models.XappSubscriptionData) bool {
438 sub := rtmgr.Subscription{SubID: *xappSubData.SubscriptionID, Fqdn: *xappSubData.Address, Port: *xappSubData.Port}
439 for _, elem := range *subs {
441 xapp.Logger.Warn("rtmgr.addSubscription: Subscription already present: %v", elem)
446 *subs = append(*subs, sub)
451 func delSubscription(subs *rtmgr.SubscriptionList, xappSubData *models.XappSubscriptionData) bool {
452 xapp.Logger.Debug("Deleteing the subscription from the subscriptions list")
454 sub := rtmgr.Subscription{SubID: *xappSubData.SubscriptionID, Fqdn: *xappSubData.Address, Port: *xappSubData.Port}
455 for i, elem := range *subs {
458 // Since the order of the list is not important, we are swapping the last element
459 // with the matching element and replacing the list with list(n-1) elements.
460 (*subs)[len(*subs)-1], (*subs)[i] = (*subs)[i], (*subs)[len(*subs)-1]
461 *subs = (*subs)[:len(*subs)-1]
465 if present == false {
466 xapp.Logger.Warn("rtmgr.delSubscription: Subscription = %v, not present in the existing subscriptions", xappSubData)