Some code refactoring, etc.
[ric-plt/xapp-frame.git] / pkg / xapp / restapi.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
20 package xapp
21
22 import (
23         "encoding/json"
24         "github.com/gorilla/mux"
25         "github.com/spf13/viper"
26         "io/ioutil"
27         "net/http"
28         "os"
29
30         "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/models"
31 )
32
33 const (
34         ReadyURL     = "/ric/v1/health/ready"
35         AliveURL     = "/ric/v1/health/alive"
36         ConfigURL    = "/ric/v1/cm/{name}"
37         AppConfigURL = "/ric/v1/config"
38 )
39
40 var (
41         healthReady bool
42 )
43
44 type StatusCb func() bool
45
46 type Router struct {
47         router *mux.Router
48         cbMap  []StatusCb
49 }
50
51 func NewRouter() *Router {
52         r := &Router{
53                 router: mux.NewRouter().StrictSlash(true),
54                 cbMap:  make([]StatusCb, 0),
55         }
56
57         // Inject default routes for health probes
58         r.InjectRoute(ReadyURL, readyHandler, "GET")
59         r.InjectRoute(AliveURL, aliveHandler, "GET")
60         r.InjectRoute(ConfigURL, configHandler, "POST")
61         r.InjectRoute(AppConfigURL, appconfigHandler, "GET")
62
63         return r
64 }
65
66 func (r *Router) serviceChecker(inner http.HandlerFunc) http.HandlerFunc {
67         return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
68                 Logger.Info("restapi: method=%s url=%s", req.Method, req.URL.RequestURI())
69                 if req.URL.RequestURI() == AliveURL || r.CheckStatus() {
70                         inner.ServeHTTP(w, req)
71                 } else {
72                         respondWithJSON(w, http.StatusServiceUnavailable, nil)
73                 }
74         })
75 }
76
77 func (r *Router) InjectRoute(url string, handler http.HandlerFunc, method string) *mux.Route {
78         return r.router.Path(url).HandlerFunc(r.serviceChecker(handler)).Methods(method)
79 }
80
81 func (r *Router) InjectQueryRoute(url string, h http.HandlerFunc, m string, q ...string) *mux.Route {
82         return r.router.Path(url).HandlerFunc(r.serviceChecker(h)).Methods(m).Queries(q...)
83 }
84
85 func (r *Router) InjectRoutePrefix(prefix string, handler http.HandlerFunc) *mux.Route {
86         return r.router.PathPrefix(prefix).HandlerFunc(r.serviceChecker(handler))
87 }
88
89 func (r *Router) InjectStatusCb(f StatusCb) {
90         r.cbMap = append(r.cbMap, f)
91 }
92
93 func (r *Router) CheckStatus() (status bool) {
94         if len(r.cbMap) == 0 {
95                 return true
96         }
97
98         for _, f := range r.cbMap {
99                 status = f()
100         }
101         return
102 }
103
104 func IsHealthProbeReady() bool {
105         return healthReady
106 }
107
108 func readyHandler(w http.ResponseWriter, r *http.Request) {
109         healthReady = true
110         respondWithJSON(w, http.StatusOK, nil)
111 }
112
113 func aliveHandler(w http.ResponseWriter, r *http.Request) {
114         respondWithJSON(w, http.StatusOK, nil)
115 }
116
117 func configHandler(w http.ResponseWriter, r *http.Request) {
118         xappName := mux.Vars(r)["name"]
119         if xappName == "" || r.Body == nil {
120                 respondWithJSON(w, http.StatusBadRequest, nil)
121                 return
122         }
123         defer r.Body.Close()
124
125         body, err := ioutil.ReadAll(r.Body)
126         if err != nil {
127                 Logger.Error("ioutil.ReadAll failed: %v", err)
128                 respondWithJSON(w, http.StatusInternalServerError, nil)
129                 return
130         }
131
132         if err := PublishConfigChange(xappName, string(body)); err != nil {
133                 respondWithJSON(w, http.StatusInternalServerError, nil)
134                 return
135         }
136
137         respondWithJSON(w, http.StatusOK, nil)
138 }
139
140 func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
141         w.Header().Set("Content-Type", "application/json")
142         w.WriteHeader(code)
143         if payload != nil {
144                 response, _ := json.Marshal(payload)
145                 w.Write(response)
146         }
147 }
148
149 func appconfigHandler(w http.ResponseWriter, r *http.Request) {
150
151         Logger.Info("Inside appconfigHandler")
152
153         var appconfig models.XappConfigList
154         var metadata models.ConfigMetadata
155         var xappconfig models.XAppConfig
156         name := viper.GetString("name")
157         configtype := "json"
158         metadata.XappName = &name
159         metadata.ConfigType = &configtype
160
161         configFile, err := os.Open("/opt/ric/config/config-file.json")
162         if err != nil {
163                 Logger.Error("Cannot open config file: %v", err)
164                 respondWithJSON(w, http.StatusInternalServerError, nil)
165                 // return nil,errors.New("Could Not parse the config file")
166         }
167
168         body, err := ioutil.ReadAll(configFile)
169
170         defer configFile.Close()
171
172         xappconfig.Metadata = &metadata
173         xappconfig.Config = string(body)
174
175         appconfig = append(appconfig, &xappconfig)
176
177         respondWithJSON(w, http.StatusOK, appconfig)
178
179         //return appconfig,nil
180 }