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) CollectDefaultSymptomData(fileName string, data interface{}) string {
124 baseDir := Config.GetString("controls.symptomdata.baseDir")
126 baseDir = "/tmp/xapp/"
129 if err := Util.CreateDir(baseDir); err != nil {
130 Logger.Error("CreateDir failed: %v", err)
134 if metrics, err := r.GetLocalMetrics(GetPortData("http").Port); err == nil {
135 if err := Util.WriteToFile(baseDir+"metrics.json", metrics); err != nil {
136 Logger.Error("writeToFile failed for metrics.json: %v", err)
141 if b, err := json.MarshalIndent(data, "", " "); err == nil {
142 Util.WriteToFile(baseDir+fileName, string(b))
146 rtPath := os.Getenv("RMR_STASH_RT")
151 input, err := ioutil.ReadFile(rtPath)
153 Logger.Error("ioutil.ReadFile failed: %v", err)
157 Util.WriteToFile(baseDir+"rttable.txt", string(input))
161 func (r *Router) SendSymptomDataJson(w http.ResponseWriter, req *http.Request, data interface{}, n string) {
162 w.Header().Set("Content-Type", "application/json")
163 w.Header().Set("Content-Disposition", "attachment; filename="+n)
164 w.WriteHeader(http.StatusOK)
166 response, _ := json.MarshalIndent(data, "", " ")
171 func (r *Router) SendSymptomDataFile(w http.ResponseWriter, req *http.Request, baseDir, zipFile string) {
172 // Compress and reply with attachment
173 tmpFile, err := ioutil.TempFile("", "symptom")
175 r.SendSymptomDataError(w, req, "Failed to create a tmp file: "+err.Error())
178 defer os.Remove(tmpFile.Name())
180 var fileList []string
181 fileList = Util.FetchFiles(baseDir, fileList)
182 err = Util.ZipFiles(tmpFile, baseDir, fileList)
184 r.SendSymptomDataError(w, req, "Failed to zip the files: "+err.Error())
188 w.Header().Set("Content-Disposition", "attachment; filename="+zipFile)
189 http.ServeFile(w, req, tmpFile.Name())
192 func (r *Router) SendSymptomDataError(w http.ResponseWriter, req *http.Request, message string) {
193 w.Header().Set("Content-Disposition", "attachment; filename=error_status.txt")
194 http.Error(w, message, http.StatusInternalServerError)
197 func (r *Router) GetLocalMetrics(port int) (string, error) {
198 resp, err := http.Get(fmt.Sprintf("http://localhost:%d/ric/v1/metrics", port))
202 defer resp.Body.Close()
204 metrics, err := ioutil.ReadAll(resp.Body)
209 return string(metrics), nil
212 func IsHealthProbeReady() bool {
216 func readyHandler(w http.ResponseWriter, r *http.Request) {
218 respondWithJSON(w, http.StatusOK, nil)
221 func aliveHandler(w http.ResponseWriter, r *http.Request) {
222 respondWithJSON(w, http.StatusOK, nil)
225 func configHandler(w http.ResponseWriter, r *http.Request) {
226 xappName := mux.Vars(r)["name"]
227 if xappName == "" || r.Body == nil {
228 respondWithJSON(w, http.StatusBadRequest, nil)
233 body, err := ioutil.ReadAll(r.Body)
235 Logger.Error("ioutil.ReadAll failed: %v", err)
236 respondWithJSON(w, http.StatusInternalServerError, nil)
240 if err := PublishConfigChange(xappName, string(body)); err != nil {
241 respondWithJSON(w, http.StatusInternalServerError, nil)
245 respondWithJSON(w, http.StatusOK, nil)
248 func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
249 w.Header().Set("Content-Type", "application/json")
252 response, _ := json.Marshal(payload)
257 func appconfigHandler(w http.ResponseWriter, r *http.Request) {
259 Logger.Info("Inside appconfigHandler")
261 var appconfig models.XappConfigList
262 var metadata models.ConfigMetadata
263 var xappconfig models.XAppConfig
264 name := viper.GetString("name")
266 metadata.XappName = &name
267 metadata.ConfigType = &configtype
269 configFile, err := os.Open("/opt/ric/config/config-file.json")
271 Logger.Error("Cannot open config file: %v", err)
272 respondWithJSON(w, http.StatusInternalServerError, nil)
273 // return nil,errors.New("Could Not parse the config file")
276 body, err := ioutil.ReadAll(configFile)
278 defer configFile.Close()
280 xappconfig.Metadata = &metadata
281 xappconfig.Config = string(body)
283 appconfig = append(appconfig, &xappconfig)
285 respondWithJSON(w, http.StatusOK, appconfig)
287 //return appconfig,nil