MEID tableupdated incrementally rather than full update
[ric-plt/rtmgr.git] / pkg / nbi / httprestful.go
1 /*
2 ==================================================================================
3   Copyright (c) 2019 AT&T Intellectual Property.
4   Copyright (c) 2019 Nokia
5
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
9
10        http://www.apache.org/licenses/LICENSE-2.0
11
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.
17
18
19    This source code is part of the near-RT RIC (RAN Intelligent Controller)
20    platform project (RICP).
21
22 ==================================================================================
23 */
24 /*
25   Mnemonic:     httprestful.go
26   Abstract:     HTTP Restful API NBI implementation
27                 Based on Swagger generated code
28   Date:         25 March 2019
29 */
30
31 package nbi
32
33 //noinspection GoUnresolvedReference,GoUnresolvedReference,GoUnresolvedReference,GoUnresolvedReference,GoUnresolvedReference,GoUnresolvedReference
34 import (
35         "encoding/json"
36         "errors"
37         "fmt"
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"
41         "net/url"
42         "net"
43         "os"
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"
51         "strconv"
52         "time"
53         "sync"
54         "strings"
55 )
56
57 //var myClient = &http.Client{Timeout: 1 * time.Second}
58
59 type HttpRestful struct {
60         Engine
61         LaunchRest                   LaunchRestHandler
62         RecvXappCallbackData         RecvXappCallbackDataHandler
63         RecvNewE2Tdata               RecvNewE2TdataHandler 
64         ProvideXappHandleHandlerImpl ProvideXappHandleHandlerImpl
65         RetrieveStartupData          RetrieveStartupDataHandler
66 }
67
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
75         return instance
76 }
77
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
89         }
90         if nil != xappData {
91                 var xapps []rtmgr.XApp
92                 err := json.Unmarshal([]byte(xappData.XApps), &xapps)
93                 return &xapps, err
94         } else {
95                 xapp.Logger.Info("No data")
96         }
97
98         xapp.Logger.Debug("Nothing received on the Http interface")
99         return nil, nil
100 }
101
102 func recvNewE2Tdata(dataChannel <-chan *models.E2tData) (*rtmgr.E2TInstance,string,error) {
103         var e2tData *models.E2tData
104         var str string
105         xapp.Logger.Info("data received")
106
107         e2tData = <-dataChannel
108
109         if nil != e2tData {
110
111                         e2tinst :=  rtmgr.E2TInstance {
112                                  Ranlist : make([]string, len(e2tData.RanNamelist)),
113                         }
114
115         e2tinst.Fqdn = *e2tData.E2TAddress
116         e2tinst.Name = "E2TERMINST"
117         copy(e2tinst.Ranlist, e2tData.RanNamelist)
118         if (len(e2tData.RanNamelist) > 0) {
119             var meidar string
120             for _, meid := range e2tData.RanNamelist {
121                 meidar += meid + " "
122             }
123             str = "mme_ar|" + *e2tData.E2TAddress + "|" + strings.TrimSuffix(meidar," ")
124         }
125         return &e2tinst,str,nil
126
127         } else {
128                 xapp.Logger.Info("No data")
129         }
130
131         xapp.Logger.Debug("Nothing received on the Http interface")
132         return nil,str,nil
133 }
134
135 func validateXappCallbackData(callbackData *models.XappCallbackData) error {
136         if len(callbackData.XApps) == 0 {
137                 return fmt.Errorf("invalid Data field: \"%s\"", callbackData.XApps)
138         }
139         var xapps []rtmgr.XApp
140         err := json.Unmarshal([]byte(callbackData.XApps), &xapps)
141         if err != nil {
142                 return fmt.Errorf("unmarshal failed: \"%s\"", err.Error())
143         }
144         return nil
145 }
146
147 func provideXappHandleHandlerImpl(datach chan<- *models.XappCallbackData, data *models.XappCallbackData) error {
148         if data != nil {
149                 xapp.Logger.Debug("Received callback data")
150         }
151         err := validateXappCallbackData(data)
152         if err != nil {
153                 xapp.Logger.Warn("XApp callback data validation failed: " + err.Error())
154                 return err
155         } else {
156                 datach <- data
157                 return nil
158         }
159 }
160
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 {
165                         err = nil
166                         break
167                 }
168         }
169         return err
170 }
171
172 func validateE2tData(data *models.E2tData) error {
173
174         e2taddress_key := *data.E2TAddress
175         if (e2taddress_key == "") {
176                 return fmt.Errorf("E2TAddress is empty!!!")
177         }
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 )
181         }
182
183         _, err := net.LookupIP(stringSlice[0])
184         if err != nil {
185                 return fmt.Errorf("E2T E2TAddress DNS look up failed, E2TAddress: %v", stringSlice[0])
186         }
187
188         if checkValidaE2TAddress(e2taddress_key) {
189                 return fmt.Errorf("E2TAddress already exist!!!, E2TAddress: %v",e2taddress_key)
190         }
191
192         return nil
193 }
194
195 func validateDeleteE2tData(data *models.E2tDeleteData) error {
196
197         if (*data.E2TAddress == "") {
198                 return fmt.Errorf("E2TAddress is empty!!!")
199         }
200
201         for _, element := range data.RanAssocList {
202                 e2taddress_key := *element.E2TAddress
203                 stringSlice := strings.Split(e2taddress_key, ":")
204
205                 if (len(stringSlice) == 1) {
206                         return fmt.Errorf("E2T Delete - RanAssocList E2TAddress is not a proper format like ip:port, %v", e2taddress_key)
207                 }
208
209
210                 if !checkValidaE2TAddress(e2taddress_key) {
211                                 return fmt.Errorf("E2TAddress doesn't exist!!!, E2TAddress: %v",e2taddress_key)
212                 }
213
214         }
215         return nil
216 }
217
218 func checkValidaE2TAddress(e2taddress string) bool {
219
220         _, exist := rtmgr.Eps[e2taddress]
221         return exist
222
223 }
224
225 func provideXappSubscriptionHandleImpl(subchan chan<- *models.XappSubscriptionData,
226         data *models.XappSubscriptionData) error {
227         xapp.Logger.Debug("Invoked provideXappSubscriptionHandleImpl")
228         err := validateXappSubscriptionData(data)
229         if err != nil {
230                 xapp.Logger.Error(err.Error())
231                 return err
232         }
233         subchan <- data
234         //var val = string(*data.Address + ":" + strconv.Itoa(int(*data.Port)))
235         xapp.Logger.Debug("Endpoints: %v", rtmgr.Eps)
236         return nil
237 }
238
239 func subscriptionExists(data *models.XappSubscriptionData) bool {
240         present := false
241         sub := rtmgr.Subscription{SubID: *data.SubscriptionID, Fqdn: *data.Address, Port: *data.Port}
242         for _, elem := range rtmgr.Subs {
243                 if elem == sub {
244                         present = true
245                         break
246                 }
247         }
248         return present
249 }
250
251 func deleteXappSubscriptionHandleImpl(subdelchan chan<- *models.XappSubscriptionData,
252         data *models.XappSubscriptionData) error {
253         xapp.Logger.Debug("Invoked deleteXappSubscriptionHandleImpl")
254         err := validateXappSubscriptionData(data)
255         if err != nil {
256                 xapp.Logger.Error(err.Error())
257                 return err
258         }
259
260         if !subscriptionExists(data) {
261                 xapp.Logger.Warn("subscription not found: %d", *data.SubscriptionID)
262                 err := fmt.Errorf("subscription not found: %d", *data.SubscriptionID)
263                 return err
264         }
265
266         subdelchan <- data
267         return nil
268 }
269
270 func createNewE2tHandleHandlerImpl(e2taddchan chan<- *models.E2tData,
271         data *models.E2tData) error {
272         xapp.Logger.Debug("Invoked createNewE2tHandleHandlerImpl")
273         err := validateE2tData(data)
274         if err != nil {
275                 xapp.Logger.Error(err.Error())
276                 return err
277         }
278         e2taddchan <- data
279         return nil
280 }
281
282 func validateE2TAddressRANListData(assRanE2tData models.RanE2tMap) error {
283
284         xapp.Logger.Debug("Invoked.validateE2TAddressRANListData : %v", assRanE2tData)
285
286         for _, element := range assRanE2tData {
287                 if *element.E2TAddress == "" {
288                         return fmt.Errorf("E2T Instance - E2TAddress is empty!!!")
289                 }
290
291                 e2taddress_key := *element.E2TAddress
292                 if !checkValidaE2TAddress(e2taddress_key) {
293                         return fmt.Errorf("E2TAddress doesn't exist!!!, E2TAddress: %v",e2taddress_key)
294                 }
295
296         }
297         return nil
298 }
299
300 func associateRanToE2THandlerImpl(assranchan chan<- models.RanE2tMap,
301         data models.RanE2tMap) error {
302         xapp.Logger.Debug("Invoked associateRanToE2THandlerImpl")
303         err := validateE2TAddressRANListData(data)
304         if err != nil {
305                 xapp.Logger.Warn(" Association of RAN to E2T Instance data validation failed: " + err.Error())
306                 return err
307         }
308         assranchan <- data
309         return nil
310 }
311
312 func disassociateRanToE2THandlerImpl(disassranchan chan<- models.RanE2tMap,
313         data models.RanE2tMap) error {
314         xapp.Logger.Debug("Invoked disassociateRanToE2THandlerImpl")
315         err := validateE2TAddressRANListData(data)
316         if err != nil {
317                 xapp.Logger.Warn(" Disassociation of RAN List from E2T Instance data validation failed: " + err.Error())
318                 return err
319         }
320         disassranchan <- data
321         return nil
322 }
323
324 func deleteE2tHandleHandlerImpl(e2tdelchan chan<- *models.E2tDeleteData,
325         data *models.E2tDeleteData) error {
326         xapp.Logger.Debug("Invoked deleteE2tHandleHandlerImpl")
327
328         err := validateDeleteE2tData(data)
329         if err != nil {
330                 xapp.Logger.Error(err.Error())
331                 return err
332         }
333
334         e2tdelchan <- data
335         return nil
336 }
337
338 func launchRest(nbiif *string, datach chan<- *models.XappCallbackData, subchan chan<- *models.XappSubscriptionData,
339         subdelchan chan<- *models.XappSubscriptionData, e2taddchan chan<- *models.E2tData, assranchan chan<- models.RanE2tMap, disassranchan chan<- models.RanE2tMap, e2tdelchan chan<- *models.E2tDeleteData) {
340         swaggerSpec, err := loads.Embedded(restapi.SwaggerJSON, restapi.FlatSwaggerJSON)
341         if err != nil {
342                 //log.Fatalln(err)
343                 xapp.Logger.Error(err.Error())
344                 os.Exit(1)
345         }
346         nbiUrl, err := url.Parse(*nbiif)
347         if err != nil {
348                 xapp.Logger.Error(err.Error())
349                 os.Exit(1)
350         }
351         api := operations.NewRoutingManagerAPI(swaggerSpec)
352         server := restapi.NewServer(api)
353         defer server.Shutdown()
354
355         server.Port, err = strconv.Atoi(nbiUrl.Port())
356         if err != nil {
357                 xapp.Logger.Error("Invalid NBI RestAPI port")
358                 os.Exit(1)
359         }
360         server.Host = "0.0.0.0"
361         // set handlers
362         api.HandleProvideXappHandleHandler = handle.ProvideXappHandleHandlerFunc(
363                 func(params handle.ProvideXappHandleParams) middleware.Responder {
364                         xapp.Logger.Info("Data received on Http interface")
365                         err := provideXappHandleHandlerImpl(datach, params.XappCallbackData)
366                         if err != nil {
367                                 xapp.Logger.Error("Invalid XApp callback data: " + err.Error())
368                                 return handle.NewProvideXappHandleBadRequest()
369                         } else {
370                                 return handle.NewGetHandlesOK()
371                         }
372                 })
373         api.HandleProvideXappSubscriptionHandleHandler = handle.ProvideXappSubscriptionHandleHandlerFunc(
374                 func(params handle.ProvideXappSubscriptionHandleParams) middleware.Responder {
375                         err := provideXappSubscriptionHandleImpl(subchan, params.XappSubscriptionData)
376                         if err != nil {
377                                 return handle.NewProvideXappSubscriptionHandleBadRequest()
378                         } else {
379                                 //Delay the reponse as add subscription channel needs to update sdl and then sbi sends updated routes to all endpoints
380                                 time.Sleep(1 * time.Second)
381                                 return handle.NewGetHandlesOK()
382                         }
383                 })
384         api.HandleDeleteXappSubscriptionHandleHandler = handle.DeleteXappSubscriptionHandleHandlerFunc(
385                 func(params handle.DeleteXappSubscriptionHandleParams) middleware.Responder {
386                         err := deleteXappSubscriptionHandleImpl(subdelchan, params.XappSubscriptionData)
387                         if err != nil {
388                                 return handle.NewDeleteXappSubscriptionHandleNoContent()
389                         } else {
390                                 //Delay the reponse as delete subscription channel needs to update sdl and then sbi sends updated routes to all endpoints
391                                 time.Sleep(1 * time.Second)
392                                 return handle.NewGetHandlesOK()
393                         }
394                 })
395        api.HandleCreateNewE2tHandleHandler = handle.CreateNewE2tHandleHandlerFunc(
396                 func(params handle.CreateNewE2tHandleParams) middleware.Responder {
397                         err := createNewE2tHandleHandlerImpl(e2taddchan, params.E2tData)
398                         if err != nil {
399                                 return handle.NewCreateNewE2tHandleBadRequest()
400                         } else {
401                                 time.Sleep(1 * time.Second)
402                                 return handle.NewCreateNewE2tHandleCreated()
403                         }
404                 })
405
406        api.HandleAssociateRanToE2tHandleHandler = handle.AssociateRanToE2tHandleHandlerFunc(
407                 func(params handle.AssociateRanToE2tHandleParams) middleware.Responder {
408                         err := associateRanToE2THandlerImpl(assranchan, params.RanE2tList)
409                         if err != nil {
410                                 return handle.NewAssociateRanToE2tHandleBadRequest()
411                         } else {
412                                 time.Sleep(1 * time.Second)
413                                 return handle.NewAssociateRanToE2tHandleCreated()
414                         }
415                 })
416
417        api.HandleDissociateRanHandler = handle.DissociateRanHandlerFunc(
418                 func(params handle.DissociateRanParams) middleware.Responder {
419                         err := disassociateRanToE2THandlerImpl(disassranchan, params.DissociateList)
420                         if err != nil {
421                                 return handle.NewDissociateRanBadRequest()
422                         } else {
423                                 time.Sleep(1 * time.Second)
424                                 return handle.NewDissociateRanCreated()
425                         }
426                 })
427
428        api.HandleDeleteE2tHandleHandler = handle.DeleteE2tHandleHandlerFunc(
429                 func(params handle.DeleteE2tHandleParams) middleware.Responder {
430                         err := deleteE2tHandleHandlerImpl(e2tdelchan, params.E2tData)
431                         if err != nil {
432                                 return handle.NewDeleteE2tHandleBadRequest()
433                         } else {
434                                 time.Sleep(1 * time.Second)
435                                 return handle.NewDeleteE2tHandleCreated()
436                         }
437                 })
438         // start to serve API
439         xapp.Logger.Info("Starting the HTTP Rest service")
440         if err := server.Serve(); err != nil {
441                 xapp.Logger.Error(err.Error())
442         }
443 }
444
445 func httpGetXApps(xmurl string) (*[]rtmgr.XApp, error) {
446         xapp.Logger.Info("Invoked httprestful.httpGetXApps: " + xmurl)
447         r, err := myClient.Get(xmurl)
448         if err != nil {
449                 return nil, err
450         }
451         defer r.Body.Close()
452
453         if r.StatusCode == 200 {
454                 xapp.Logger.Debug("http client raw response: %v", r)
455                 var xapps []rtmgr.XApp
456                 err = json.NewDecoder(r.Body).Decode(&xapps)
457                 if err != nil {
458                         xapp.Logger.Warn("Json decode failed: " + err.Error())
459                 }
460                 xapp.Logger.Info("HTTP GET: OK")
461                 xapp.Logger.Debug("httprestful.httpGetXApps returns: %v", xapps)
462                 return &xapps, err
463         }
464         xapp.Logger.Warn("httprestful got an unexpected http status code: %v", r.StatusCode)
465         return nil, nil
466 }
467
468 func retrieveStartupData(xmurl string, nbiif string, fileName string, configfile string, sdlEngine sdl.Engine) error {
469         var readErr error
470         var maxRetries = 10
471         for i := 1; i <= maxRetries; i++ {
472                 time.Sleep(2 * time.Second)
473                 xappData, err := httpGetXApps(xmurl)
474                 if xappData != nil && err == nil {
475                         pcData, confErr := rtmgr.GetPlatformComponents(configfile)
476                         if confErr != nil {
477                                 xapp.Logger.Error(confErr.Error())
478                                 return confErr
479                         }
480                         xapp.Logger.Info("Recieved intial xapp data and platform data, writing into SDL.")
481                         // Combine the xapps data and platform data before writing to the SDL
482                         ricData := &rtmgr.RicComponents{XApps: *xappData, Pcs: *pcData, E2Ts:  make(map[string]rtmgr.E2TInstance)}
483                         writeErr := sdlEngine.WriteAll(fileName, ricData)
484                         if writeErr != nil {
485                                 xapp.Logger.Error(writeErr.Error())
486                         }
487                         // post subscription req to appmgr
488                         readErr = PostSubReq(xmurl, nbiif)
489                         if readErr == nil {
490                                 return nil
491                         }
492                 } else if err == nil {
493                         readErr = errors.New("unexpected HTTP status code")
494                 } else {
495                         xapp.Logger.Warn("cannot get xapp data due to: " + err.Error())
496                         readErr = err
497                 }
498         }
499         return readErr
500 }
501
502 func (r *HttpRestful) Initialize(xmurl string, nbiif string, fileName string, configfile string,
503         sdlEngine sdl.Engine, rpeEngine rpe.Engine, triggerSBI chan<- bool, m *sync.Mutex) error {
504         err := r.RetrieveStartupData(xmurl, nbiif, fileName, configfile, sdlEngine)
505         if err != nil {
506                 xapp.Logger.Error("Exiting as nbi failed to get the initial startup data from the xapp manager: " + err.Error())
507                 return err
508         }
509
510         datach := make(chan *models.XappCallbackData, 10)
511         subschan := make(chan *models.XappSubscriptionData, 10)
512         subdelchan := make(chan *models.XappSubscriptionData, 10)
513         e2taddchan := make(chan *models.E2tData, 10)
514         associateranchan := make(chan models.RanE2tMap, 10)
515         disassociateranchan := make(chan models.RanE2tMap, 10)
516         e2tdelchan := make(chan *models.E2tDeleteData, 10)
517         xapp.Logger.Info("Launching Rest Http service")
518         go func() {
519                 r.LaunchRest(&nbiif, datach, subschan, subdelchan, e2taddchan, associateranchan, disassociateranchan, e2tdelchan)
520         }()
521
522         go func() {
523                 for {
524                         data, err := r.RecvXappCallbackData(datach)
525                         if err != nil {
526                                 xapp.Logger.Error("cannot get data from rest api dute to: " + err.Error())
527                         } else if data != nil {
528                                 xapp.Logger.Debug("Fetching all xApps deployed in xApp Manager through GET operation.")
529                                 alldata, err1 := httpGetXApps(xmurl)
530                                 if alldata != nil && err1 == nil {
531                                         m.Lock()
532                                         sdlEngine.WriteXApps(fileName, alldata)
533                                         m.Unlock()
534                                         triggerSBI <- true
535                                 }
536                         }
537                 }
538         }()
539
540         go func() {
541                 for {
542                         data := <-subschan
543                         xapp.Logger.Debug("received XApp subscription data")
544                         addSubscription(&rtmgr.Subs, data)
545                         triggerSBI <- true
546                 }
547         }()
548
549         go func() {
550                 for {
551                         data := <-subdelchan
552                         xapp.Logger.Debug("received XApp subscription delete data")
553                         delSubscription(&rtmgr.Subs, data)
554                         triggerSBI <- true
555                 }
556         }()
557
558         go func() {
559                 for {
560                         xapp.Logger.Debug("received create New E2T data")
561
562                         data, meiddata,_ := r.RecvNewE2Tdata(e2taddchan)
563                         if data != nil {
564                                 m.Lock()
565                                 sdlEngine.WriteNewE2TInstance(fileName, data,meiddata)
566                                 m.Unlock()
567                                 triggerSBI <- true
568                         }
569                 }
570         }()
571
572         go func() {
573                 for {
574                         data := <-associateranchan
575                         xapp.Logger.Debug("received associate RAN list to E2T instance mapping from E2 Manager")
576                         m.Lock()
577                         sdlEngine.WriteAssRANToE2TInstance(fileName, data)
578                         m.Unlock()
579                         triggerSBI <- true
580                 }
581         }()
582
583         go func() {
584                 for {
585
586                         data := <-disassociateranchan
587                         xapp.Logger.Debug("received disassociate RANs from E2T instance")
588                         m.Lock()
589                         sdlEngine.WriteDisAssRANFromE2TInstance(fileName, data)
590                         m.Unlock()
591                         triggerSBI <- true
592                 }
593         }()
594
595         go func() {
596                 for {
597                         xapp.Logger.Debug("received Delete E2T data")
598
599                         data := <-e2tdelchan
600                         if data != nil {
601                                 m.Lock()
602                                 sdlEngine.WriteDeleteE2TInstance(fileName, data)
603                                 m.Unlock()
604                                 triggerSBI <- true
605                         }
606                 }
607         }()
608
609         return nil
610 }
611
612 func (r *HttpRestful) Terminate() error {
613         return nil
614 }
615
616 func addSubscription(subs *rtmgr.SubscriptionList, xappSubData *models.XappSubscriptionData) bool {
617         var b = false
618         sub := rtmgr.Subscription{SubID: *xappSubData.SubscriptionID, Fqdn: *xappSubData.Address, Port: *xappSubData.Port}
619         for _, elem := range *subs {
620                 if elem == sub {
621                         xapp.Logger.Warn("rtmgr.addSubscription: Subscription already present: %v", elem)
622                         b = true
623                 }
624         }
625         if b == false {
626                 *subs = append(*subs, sub)
627         }
628         return b
629 }
630
631 func delSubscription(subs *rtmgr.SubscriptionList, xappSubData *models.XappSubscriptionData) bool {
632         xapp.Logger.Debug("Deleteing the subscription from the subscriptions list")
633         var present = false
634         sub := rtmgr.Subscription{SubID: *xappSubData.SubscriptionID, Fqdn: *xappSubData.Address, Port: *xappSubData.Port}
635         for i, elem := range *subs {
636                 if elem == sub {
637                         present = true
638                         // Since the order of the list is not important, we are swapping the last element
639                         // with the matching element and replacing the list with list(n-1) elements.
640                         (*subs)[len(*subs)-1], (*subs)[i] = (*subs)[i], (*subs)[len(*subs)-1]
641                         *subs = (*subs)[:len(*subs)-1]
642                         break
643                 }
644         }
645         if present == false {
646                 xapp.Logger.Warn("rtmgr.delSubscription: Subscription = %v, not present in the existing subscriptions", xappSubData)
647         }
648         return present
649 }