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.
17 ==================================================================================
25 "github.com/gorilla/mux"
26 "github.com/spf13/viper"
31 "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/models"
35 ReadyURL = "/ric/v1/health/ready"
36 AliveURL = "/ric/v1/health/alive"
37 ConfigURL = "/ric/v1/cm/{name}"
38 AppConfigURL = "/ric/v1/config"
45 type StatusCb func() bool
52 func NewRouter() *Router {
54 router: mux.NewRouter().StrictSlash(true),
55 cbMap: make([]StatusCb, 0),
58 // Inject default routes for health probes
59 r.InjectRoute(ReadyURL, readyHandler, "GET")
60 r.InjectRoute(AliveURL, aliveHandler, "GET")
61 r.InjectRoute(ConfigURL, configHandler, "POST")
62 r.InjectRoute(AppConfigURL, appconfigHandler, "GET")
67 func (r *Router) serviceChecker(inner http.HandlerFunc) http.HandlerFunc {
68 return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
69 Logger.Info("restapi: method=%s url=%s", req.Method, req.URL.RequestURI())
70 if req.URL.RequestURI() == AliveURL || r.CheckStatus() {
71 inner.ServeHTTP(w, req)
73 respondWithJSON(w, http.StatusServiceUnavailable, nil)
78 func (r *Router) InjectRoute(url string, handler http.HandlerFunc, method string) *mux.Route {
79 return r.router.Path(url).HandlerFunc(r.serviceChecker(handler)).Methods(method)
82 func (r *Router) InjectQueryRoute(url string, h http.HandlerFunc, m string, q ...string) *mux.Route {
83 return r.router.Path(url).HandlerFunc(r.serviceChecker(h)).Methods(m).Queries(q...)
86 func (r *Router) InjectRoutePrefix(prefix string, handler http.HandlerFunc) *mux.Route {
87 return r.router.PathPrefix(prefix).HandlerFunc(r.serviceChecker(handler))
90 func (r *Router) InjectStatusCb(f StatusCb) {
91 r.cbMap = append(r.cbMap, f)
94 func (r *Router) CheckStatus() (status bool) {
95 if len(r.cbMap) == 0 {
99 for _, f := range r.cbMap {
105 func (r *Router) GetSymptomDataParams(w http.ResponseWriter, req *http.Request) SymptomDataParams {
106 params := SymptomDataParams{}
107 queryParams := req.URL.Query()
109 for p := range queryParams {
111 fmt.Sscanf(p, "%d", ¶ms.Timeout)
114 fmt.Sscanf(p, "%d", ¶ms.FromTime)
117 fmt.Sscanf(p, "%d", ¶ms.ToTime)
123 func (r *Router) SendSymptomDataJson(w http.ResponseWriter, req *http.Request, data interface{}, n string) {
124 w.Header().Set("Content-Type", "application/json")
125 w.Header().Set("Content-Disposition", "attachment; filename="+n)
126 w.WriteHeader(http.StatusOK)
128 response, _ := json.Marshal(data)
133 func (r *Router) SendSymptomDataFile(w http.ResponseWriter, req *http.Request, baseDir, zipFile string) {
134 // Compress and reply with attachment
135 tmpFile, err := ioutil.TempFile("", "symptom")
137 r.SendSymptomDataError(w, req, "Failed to create a tmp file: "+err.Error())
140 defer os.Remove(tmpFile.Name())
142 var fileList []string
143 fileList = Util.FetchFiles(baseDir, fileList)
144 err = Util.ZipFiles(tmpFile, baseDir, fileList)
146 r.SendSymptomDataError(w, req, "Failed to zip the files: "+err.Error())
150 w.Header().Set("Content-Disposition", "attachment; filename="+zipFile)
151 http.ServeFile(w, req, tmpFile.Name())
154 func (r *Router) SendSymptomDataError(w http.ResponseWriter, req *http.Request, message string) {
155 w.Header().Set("Content-Disposition", "attachment; filename=error_status.txt")
156 http.Error(w, message, http.StatusInternalServerError)
159 func IsHealthProbeReady() bool {
163 func readyHandler(w http.ResponseWriter, r *http.Request) {
165 respondWithJSON(w, http.StatusOK, nil)
168 func aliveHandler(w http.ResponseWriter, r *http.Request) {
169 respondWithJSON(w, http.StatusOK, nil)
172 func configHandler(w http.ResponseWriter, r *http.Request) {
173 xappName := mux.Vars(r)["name"]
174 if xappName == "" || r.Body == nil {
175 respondWithJSON(w, http.StatusBadRequest, nil)
180 body, err := ioutil.ReadAll(r.Body)
182 Logger.Error("ioutil.ReadAll failed: %v", err)
183 respondWithJSON(w, http.StatusInternalServerError, nil)
187 if err := PublishConfigChange(xappName, string(body)); err != nil {
188 respondWithJSON(w, http.StatusInternalServerError, nil)
192 respondWithJSON(w, http.StatusOK, nil)
195 func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
196 w.Header().Set("Content-Type", "application/json")
199 response, _ := json.Marshal(payload)
204 func appconfigHandler(w http.ResponseWriter, r *http.Request) {
206 Logger.Info("Inside appconfigHandler")
208 var appconfig models.XappConfigList
209 var metadata models.ConfigMetadata
210 var xappconfig models.XAppConfig
211 name := viper.GetString("name")
213 metadata.XappName = &name
214 metadata.ConfigType = &configtype
216 configFile, err := os.Open("/opt/ric/config/config-file.json")
218 Logger.Error("Cannot open config file: %v", err)
219 respondWithJSON(w, http.StatusInternalServerError, nil)
220 // return nil,errors.New("Could Not parse the config file")
223 body, err := ioutil.ReadAll(configFile)
225 defer configFile.Close()
227 xappconfig.Metadata = &metadata
228 xappconfig.Config = string(body)
230 appconfig = append(appconfig, &xappconfig)
232 respondWithJSON(w, http.StatusOK, appconfig)
234 //return appconfig,nil