blob: 86f2cf0c01958bb8a014a097bb324d36d4268102 [file] [log] [blame]
Mohamed Abukar34e43832019-11-13 17:57:15 +02001/*
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
20package restful
21
22import (
wahidwd8726302020-12-13 17:34:29 +000023 "encoding/json"
24 "errors"
25 "fmt"
26 //"io/ioutil"
Mohamed Abukar34e43832019-11-13 17:57:15 +020027 "log"
wahidwd8726302020-12-13 17:34:29 +000028 "net/http"
Mohamed Abukar34e43832019-11-13 17:57:15 +020029 "os"
wahidwd8726302020-12-13 17:34:29 +000030 "strconv"
31 "strings"
Mohamed Abukar34e43832019-11-13 17:57:15 +020032 "time"
33
Abukar Mohamedf8b99662020-03-02 14:44:30 +000034 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/models"
35 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/restapi"
36 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/restapi/operations"
37 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/restapi/operations/health"
38 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/restapi/operations/xapp"
Mohamed Abukar34e43832019-11-13 17:57:15 +020039 "github.com/go-openapi/loads"
40 "github.com/go-openapi/runtime/middleware"
wahidwd8726302020-12-13 17:34:29 +000041 "github.com/valyala/fastjson"
Mohamed Abukar34e43832019-11-13 17:57:15 +020042
Abukar Mohamedf8b99662020-03-02 14:44:30 +000043 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/appmgr"
Abukar Mohamedf8b99662020-03-02 14:44:30 +000044 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/resthooks"
Mohamed Abukar34e43832019-11-13 17:57:15 +020045)
46
wahidwd8726302020-12-13 17:34:29 +000047type XappData struct {
wahidw382755b2021-01-18 13:00:57 +000048 httpendpoint string
49 rmrendpoint string
50 rmrserviceep string
51 status string
52 xappname string
53 xappinstname string
54 xappversion string
55 xappconfigpath string
56 xappdynamiconfig bool
57 xappInstance *models.XappInstance
wahidwd8726302020-12-13 17:34:29 +000058}
59
60var xappmap = map[string]map[string]*XappData{}
61
Mohamed Abukar34e43832019-11-13 17:57:15 +020062func NewRestful() *Restful {
63 r := &Restful{
Mohamed Abukard9769772019-11-20 20:39:06 +020064 rh: resthooks.NewResthook(true),
Mohamed Abukar34e43832019-11-13 17:57:15 +020065 ready: false,
66 }
67 r.api = r.SetupHandler()
68 return r
69}
70
71func (r *Restful) Run() {
72 server := restapi.NewServer(r.api)
73 defer server.Shutdown()
Mohamed Abukard9769772019-11-20 20:39:06 +020074 server.Port = 8080
75 server.Host = "0.0.0.0"
Mohamed Abukar34e43832019-11-13 17:57:15 +020076
77 appmgr.Logger.Info("Xapp manager started ... serving on %s:%d\n", server.Host, server.Port)
78
wahidwd8726302020-12-13 17:34:29 +000079 go r.RetrieveApps()
Mohamed Abukar34e43832019-11-13 17:57:15 +020080 if err := server.Serve(); err != nil {
81 log.Fatal(err.Error())
82 }
wahidwd8726302020-12-13 17:34:29 +000083
84}
85
86func (r *Restful) RetrieveApps() {
87 time.Sleep(5 * time.Second)
88 var xlist models.RegisterRequest
89 applist := r.rh.GetAppsInSDL()
90 if applist != nil {
91 appmgr.Logger.Info("List obtained from GetAppsInSDL is %s", *applist)
92 newstring := strings.Split(*applist, " ")
93 for i, _ := range newstring {
94 appmgr.Logger.Debug("Checking for xapp %s", newstring[i])
95 if newstring[i] != "" {
96 err := json.Unmarshal([]byte(newstring[i]), &xlist)
97 if err != nil {
98 appmgr.Logger.Error("Error while unmarshalling")
99 continue
100 }
101 } else {
102 continue //SDL may have empty item,so need to skip
103 }
104
105 xmodel, _ := r.PrepareConfig(xlist, false)
106 if xmodel == nil {
107 appmgr.Logger.Error("Xapp not found, deleting it from DB")
108 r.rh.UpdateAppData(xlist, true)
109 }
110 }
111 }
112
Mohamed Abukar34e43832019-11-13 17:57:15 +0200113}
114
115func (r *Restful) SetupHandler() *operations.AppManagerAPI {
116 swaggerSpec, err := loads.Embedded(restapi.SwaggerJSON, restapi.FlatSwaggerJSON)
117 if err != nil {
118 appmgr.Logger.Error(err.Error())
119 os.Exit(1)
120 }
121 api := operations.NewAppManagerAPI(swaggerSpec)
122
123 // URL: /ric/v1/health
124 api.HealthGetHealthAliveHandler = health.GetHealthAliveHandlerFunc(
125 func(params health.GetHealthAliveParams) middleware.Responder {
126 return health.NewGetHealthAliveOK()
127 })
Mohamed Abukaraca8f3c2020-01-14 11:10:16 +0200128
wahidwd8726302020-12-13 17:34:29 +0000129 api.HealthGetHealthReadyHandler = health.GetHealthReadyHandlerFunc(
Mohamed Abukar34e43832019-11-13 17:57:15 +0200130 func(params health.GetHealthReadyParams) middleware.Responder {
131 return health.NewGetHealthReadyOK()
132 })
133
134 // URL: /ric/v1/subscriptions
135 api.GetSubscriptionsHandler = operations.GetSubscriptionsHandlerFunc(
136 func(params operations.GetSubscriptionsParams) middleware.Responder {
137 return operations.NewGetSubscriptionsOK().WithPayload(r.rh.GetAllSubscriptions())
138 })
Mohamed Abukaraca8f3c2020-01-14 11:10:16 +0200139
Mohamed Abukar34e43832019-11-13 17:57:15 +0200140 api.GetSubscriptionByIDHandler = operations.GetSubscriptionByIDHandlerFunc(
141 func(params operations.GetSubscriptionByIDParams) middleware.Responder {
142 if result, found := r.rh.GetSubscriptionById(params.SubscriptionID); found {
143 return operations.NewGetSubscriptionByIDOK().WithPayload(&result)
144 }
145 return operations.NewGetSubscriptionByIDNotFound()
146 })
Mohamed Abukaraca8f3c2020-01-14 11:10:16 +0200147
Mohamed Abukar34e43832019-11-13 17:57:15 +0200148 api.AddSubscriptionHandler = operations.AddSubscriptionHandlerFunc(
149 func(params operations.AddSubscriptionParams) middleware.Responder {
150 return operations.NewAddSubscriptionCreated().WithPayload(r.rh.AddSubscription(*params.SubscriptionRequest))
151 })
Mohamed Abukaraca8f3c2020-01-14 11:10:16 +0200152
Mohamed Abukar34e43832019-11-13 17:57:15 +0200153 api.ModifySubscriptionHandler = operations.ModifySubscriptionHandlerFunc(
154 func(params operations.ModifySubscriptionParams) middleware.Responder {
155 if _, ok := r.rh.ModifySubscription(params.SubscriptionID, *params.SubscriptionRequest); ok {
156 return operations.NewModifySubscriptionOK()
157 }
158 return operations.NewModifySubscriptionBadRequest()
159 })
Mohamed Abukaraca8f3c2020-01-14 11:10:16 +0200160
Mohamed Abukar34e43832019-11-13 17:57:15 +0200161 api.DeleteSubscriptionHandler = operations.DeleteSubscriptionHandlerFunc(
162 func(params operations.DeleteSubscriptionParams) middleware.Responder {
163 if _, ok := r.rh.DeleteSubscription(params.SubscriptionID); ok {
164 return operations.NewDeleteSubscriptionNoContent()
165 }
166 return operations.NewDeleteSubscriptionBadRequest()
167 })
168
169 // URL: /ric/v1/xapp
170 api.XappGetAllXappsHandler = xapp.GetAllXappsHandlerFunc(
171 func(params xapp.GetAllXappsParams) middleware.Responder {
wahidwd8726302020-12-13 17:34:29 +0000172 if result, err := r.GetApps(); err == nil {
Mohamed Abukar34e43832019-11-13 17:57:15 +0200173 return xapp.NewGetAllXappsOK().WithPayload(result)
174 }
175 return xapp.NewGetAllXappsInternalServerError()
176 })
Mohamed Abukaraca8f3c2020-01-14 11:10:16 +0200177
wahidw78c892e2021-01-09 06:02:22 +0000178 // URL: /ric/v1/config
179 api.XappGetAllXappConfigHandler = xapp.GetAllXappConfigHandlerFunc(
180 func(params xapp.GetAllXappConfigParams) middleware.Responder {
181 return xapp.NewGetAllXappConfigOK().WithPayload(r.getAppConfig())
182 })
183
wahidwd8726302020-12-13 17:34:29 +0000184 api.RegisterXappHandler = operations.RegisterXappHandlerFunc(
185 func(params operations.RegisterXappParams) middleware.Responder {
186 appmgr.Logger.Info("appname is %s", (*params.RegisterRequest.AppName))
187 appmgr.Logger.Info("endpoint is %s", (*params.RegisterRequest.HTTPEndpoint))
188 appmgr.Logger.Info("rmrendpoint is %s", (*params.RegisterRequest.RmrEndpoint))
189 if result, err := r.RegisterXapp(*params.RegisterRequest); err == nil {
190 go r.rh.PublishSubscription(*result, models.EventTypeDeployed)
191 return operations.NewRegisterXappCreated()
Mohamed Abukar34e43832019-11-13 17:57:15 +0200192 }
wahidwd8726302020-12-13 17:34:29 +0000193 return operations.NewRegisterXappBadRequest()
Mohamed Abukar34e43832019-11-13 17:57:15 +0200194 })
Mohamed Abukaraca8f3c2020-01-14 11:10:16 +0200195
wahidwd8726302020-12-13 17:34:29 +0000196 api.DeregisterXappHandler = operations.DeregisterXappHandlerFunc(
197 func(params operations.DeregisterXappParams) middleware.Responder {
198 appmgr.Logger.Info("appname is %s", (*params.DeregisterRequest.AppName))
199 if result, err := r.DeregisterXapp(*params.DeregisterRequest); err == nil {
200 go r.rh.PublishSubscription(*result, models.EventTypeUndeployed)
201 return operations.NewDeregisterXappNoContent()
Mohamed Abukar34e43832019-11-13 17:57:15 +0200202 }
wahidwd8726302020-12-13 17:34:29 +0000203 return operations.NewDeregisterXappBadRequest()
Mohamed Abukar34e43832019-11-13 17:57:15 +0200204 })
Mohamed Abukar34e43832019-11-13 17:57:15 +0200205
206 return api
207}
208
wahidw78c892e2021-01-09 06:02:22 +0000209func httpGetXAppsconfig(url string) *string {
wahidwd8726302020-12-13 17:34:29 +0000210 appmgr.Logger.Info("Invoked httprestful.httpGetXApps: " + url)
211 resp, err := http.Get(url)
212 if err != nil {
wahidw78c892e2021-01-09 06:02:22 +0000213 return nil
Mohamed Abukar34e43832019-11-13 17:57:15 +0200214 }
wahidwd8726302020-12-13 17:34:29 +0000215 defer resp.Body.Close()
Mohamed Abukar34e43832019-11-13 17:57:15 +0200216
wahidwd8726302020-12-13 17:34:29 +0000217 if resp.StatusCode == http.StatusOK {
218 var data XappConfigList
219 appmgr.Logger.Info("http client raw response: %v", resp)
220 if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
221 appmgr.Logger.Error("Json decode failed: " + err.Error())
wahidw78c892e2021-01-09 06:02:22 +0000222 return nil
Mohamed Abukar34e43832019-11-13 17:57:15 +0200223 }
wahidwd8726302020-12-13 17:34:29 +0000224 //data[0] assuming only for one app
225 str := fmt.Sprintf("%v", data[0].Config)
226 appmgr.Logger.Info("HTTP BODY: %v", str)
227
228 resp.Body.Close()
wahidw78c892e2021-01-09 06:02:22 +0000229 return &str
230 } else {
231 appmgr.Logger.Info("httprestful got an unexpected http status code: %v", resp.StatusCode)
232 return nil
233 }
234}
wahidwd8726302020-12-13 17:34:29 +0000235
wahidw78c892e2021-01-09 06:02:22 +0000236func parseConfig(config *string) *appmgr.RtmData {
237 var p fastjson.Parser
238 var msgs appmgr.RtmData
wahidwd8726302020-12-13 17:34:29 +0000239
wahidw78c892e2021-01-09 06:02:22 +0000240 v, err := p.Parse(*config)
241 if err != nil {
242 appmgr.Logger.Info("fastjson.Parser for failed: %v", err)
243 return nil
244 }
245
246 if v.Exists("rmr") {
247 for _, m := range v.GetArray("rmr", "txMessages") {
248 msgs.TxMessages = append(msgs.TxMessages, strings.Trim(m.String(), `"`))
wahidwd8726302020-12-13 17:34:29 +0000249 }
250
wahidw78c892e2021-01-09 06:02:22 +0000251 for _, m := range v.GetArray("rmr", "rxMessages") {
252 msgs.RxMessages = append(msgs.RxMessages, strings.Trim(m.String(), `"`))
253 }
254
255 for _, m := range v.GetArray("rmr", "policies") {
256 if val, err := strconv.Atoi(strings.Trim(m.String(), `"`)); err == nil {
257 msgs.Policies = append(msgs.Policies, int64(val))
258 }
259 }
260 } else {
261 for _, p := range v.GetArray("messaging", "ports") {
262 appmgr.Logger.Info("txMessages=%v, rxMessages=%v", p.GetArray("txMessages"), p.GetArray("rxMessages"))
263 for _, m := range p.GetArray("txMessages") {
wahidwd8726302020-12-13 17:34:29 +0000264 msgs.TxMessages = append(msgs.TxMessages, strings.Trim(m.String(), `"`))
265 }
266
wahidw78c892e2021-01-09 06:02:22 +0000267 for _, m := range p.GetArray("rxMessages") {
wahidwd8726302020-12-13 17:34:29 +0000268 msgs.RxMessages = append(msgs.RxMessages, strings.Trim(m.String(), `"`))
269 }
270
wahidw78c892e2021-01-09 06:02:22 +0000271 for _, m := range p.GetArray("policies") {
wahidwd8726302020-12-13 17:34:29 +0000272 if val, err := strconv.Atoi(strings.Trim(m.String(), `"`)); err == nil {
273 msgs.Policies = append(msgs.Policies, int64(val))
274 }
275 }
wahidwd8726302020-12-13 17:34:29 +0000276 }
wahidwd8726302020-12-13 17:34:29 +0000277 }
wahidw78c892e2021-01-09 06:02:22 +0000278 return &msgs
wahidwd8726302020-12-13 17:34:29 +0000279}
280
281func (r *Restful) RegisterXapp(params models.RegisterRequest) (xapp *models.Xapp, err error) {
282 return r.PrepareConfig(params, true)
283}
284
285func (r *Restful) DeregisterXapp(params models.DeregisterRequest) (xapp *models.Xapp, err error) {
286 var registeredlist models.RegisterRequest
287 registeredlist.AppName = params.AppName
288 registeredlist.AppInstanceName = params.AppInstanceName
289 if _, found := xappmap[*params.AppName]; found {
290 var x models.Xapp
291 x.Instances = append(x.Instances, xappmap[*params.AppName][*params.AppInstanceName].xappInstance)
292 registeredlist.HTTPEndpoint = &xappmap[*params.AppName][*params.AppInstanceName].httpendpoint
293 delete(xappmap[*params.AppName], *params.AppInstanceName)
294 if len(xappmap[*params.AppName]) == 0 {
295 delete(xappmap, *params.AppName)
296 }
297 r.rh.UpdateAppData(registeredlist, true)
298 return &x, nil
299 } else {
300 appmgr.Logger.Error("XApp Instance %v Not Found", *params.AppName)
301 return nil, errors.New("XApp Instance Not Found")
Mohamed Abukar34e43832019-11-13 17:57:15 +0200302 }
303}
304
wahidwd8726302020-12-13 17:34:29 +0000305func (r *Restful) PrepareConfig(params models.RegisterRequest, updateflag bool) (xapp *models.Xapp, err error) {
306 maxRetries := 5
wahidw382755b2021-01-18 13:00:57 +0000307 configPresent := false
308 var xappconfig *string
wahidwd8726302020-12-13 17:34:29 +0000309 appmgr.Logger.Info("http endpoint is %s", *params.HTTPEndpoint)
310 for i := 1; i <= maxRetries; i++ {
wahidw382755b2021-01-18 13:00:57 +0000311 if params.Config != "" {
312 appmgr.Logger.Info("Getting config during xapp register: %v", params.Config)
313 xappconfig = &params.Config
314 configPresent = true
315 } else {
316 appmgr.Logger.Info("Getting config from xapp:")
317 xappconfig = httpGetXAppsconfig(fmt.Sprintf("http://%s%s", *params.HTTPEndpoint, params.ConfigPath))
318 }
wahidwd8726302020-12-13 17:34:29 +0000319
wahidw78c892e2021-01-09 06:02:22 +0000320 if xappconfig != nil {
321 data := parseConfig(xappconfig)
322 if data != nil {
323 appmgr.Logger.Info("iRetry Count = %v", i)
324 var xapp models.Xapp
wahidwd8726302020-12-13 17:34:29 +0000325
wahidw78c892e2021-01-09 06:02:22 +0000326 xapp.Name = params.AppName
327 xapp.Version = params.AppVersion
328 //xapp.Status = params.Status
wahidwd8726302020-12-13 17:34:29 +0000329
wahidw78c892e2021-01-09 06:02:22 +0000330 r.rh.UpdateAppData(params, updateflag)
wahidw382755b2021-01-18 13:00:57 +0000331 return r.FillInstanceData(params, &xapp, *data, configPresent)
wahidw78c892e2021-01-09 06:02:22 +0000332 break
333 } else {
wahidw382755b2021-01-18 13:00:57 +0000334 appmgr.Logger.Error("No Data from xapp")
335 }
336 if configPresent == true {
337 break
wahidw78c892e2021-01-09 06:02:22 +0000338 }
339 time.Sleep(2 * time.Second)
wahidwd8726302020-12-13 17:34:29 +0000340 }
wahidwd8726302020-12-13 17:34:29 +0000341 }
wahidwd8726302020-12-13 17:34:29 +0000342 return nil, errors.New("Unable to get configmap after 5 retries")
343}
344
wahidw382755b2021-01-18 13:00:57 +0000345func (r *Restful) FillInstanceData(params models.RegisterRequest, xapp *models.Xapp, rtData appmgr.RtmData, configFlag bool) (xapps *models.Xapp, err error) {
wahidwd8726302020-12-13 17:34:29 +0000346
wahidwd8726302020-12-13 17:34:29 +0000347 endPointStr := strings.Split(*params.RmrEndpoint, ":")
348 var x models.XappInstance
349 x.Name = params.AppInstanceName
350 //x.Status = strings.ToLower(params.Status)
351 x.Status = "deployed"
wahidw78c892e2021-01-09 06:02:22 +0000352 //x.IP = endPointStr[0]
353 x.IP = fmt.Sprintf("service-ricxapp-%s-rmr.ricxapp", *params.AppInstanceName)
wahidwd8726302020-12-13 17:34:29 +0000354 x.Port, _ = strconv.ParseInt(endPointStr[1], 10, 64)
355 x.TxMessages = rtData.TxMessages
356 x.RxMessages = rtData.RxMessages
357 x.Policies = rtData.Policies
358 xapp.Instances = append(xapp.Instances, &x)
wahidw78c892e2021-01-09 06:02:22 +0000359 rmrsrvname := fmt.Sprintf("service-ricxapp-%s-rmr.ricxapp:%s", *params.AppInstanceName, x.Port)
wahidwd8726302020-12-13 17:34:29 +0000360
wahidw78c892e2021-01-09 06:02:22 +0000361 a := &XappData{httpendpoint: *params.HTTPEndpoint,
wahidw382755b2021-01-18 13:00:57 +0000362 rmrendpoint: *params.RmrEndpoint,
363 rmrserviceep: rmrsrvname,
364 status: "deployed",
365 xappname: *params.AppName,
366 xappversion: params.AppVersion,
367 xappinstname: *params.AppInstanceName,
368 xappconfigpath: params.ConfigPath,
369 xappdynamiconfig: configFlag,
370 xappInstance: &x}
wahidwd8726302020-12-13 17:34:29 +0000371
372 if _, ok := xappmap[*params.AppName]; ok {
373 xappmap[*params.AppName][*params.AppInstanceName] = a
374 appmgr.Logger.Info("appname already present, %v", xappmap[*params.AppName])
375 } else {
376 xappmap[*params.AppName] = make(map[string]*XappData)
377 xappmap[*params.AppName][*params.AppInstanceName] = a
378 appmgr.Logger.Info("Creating app instance, %v", xappmap[*params.AppName])
379 }
380
381 return xapp, nil
382
383}
384
385func (r *Restful) GetApps() (xapps models.AllDeployedXapps, err error) {
386 xapps = models.AllDeployedXapps{}
387 for _, v := range xappmap {
388 var x models.Xapp
389 for i, j := range v {
390 x.Status = j.status
391 x.Name = &j.xappname
392 x.Version = j.xappversion
393 appmgr.Logger.Info("Xapps details currently in map Appname = %v,rmrendpoint = %v,Status = %v", i, j.rmrendpoint, j.status)
394 x.Instances = append(x.Instances, j.xappInstance)
395 }
396 xapps = append(xapps, &x)
397 }
398
399 return xapps, nil
400
Mohamed Abukar34e43832019-11-13 17:57:15 +0200401}
wahidw78c892e2021-01-09 06:02:22 +0000402
403func (r *Restful) getAppConfig() (configList models.AllXappConfig) {
404 for _, v := range xappmap {
wahidw382755b2021-01-18 13:00:57 +0000405 namespace := "ricxapp" //Namespace hardcoded, to be removed later
wahidw78c892e2021-01-09 06:02:22 +0000406 for _, j := range v {
407 var activeConfig interface{}
wahidw382755b2021-01-18 13:00:57 +0000408 if j.xappdynamiconfig {
409 continue
410 }
wahidw78c892e2021-01-09 06:02:22 +0000411 xappconfig := httpGetXAppsconfig(fmt.Sprintf("http://%s%s", j.httpendpoint, j.xappconfigpath))
412
413 if xappconfig == nil {
414 appmgr.Logger.Info("config not found for %s", &j.xappname)
415 continue
416 }
417 json.Unmarshal([]byte(*xappconfig), &activeConfig)
418
419 c := models.XAppConfig{
420 Metadata: &models.ConfigMetadata{XappName: &j.xappname, Namespace: &namespace},
421 Config: activeConfig,
422 }
423 configList = append(configList, &c)
424
425 }
426
427 }
428 return
429}