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 ==================================================================================
29 "github.com/gorilla/mux"
30 "github.com/spf13/viper"
32 "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/models"
36 ReadyURL = "/ric/v1/health/ready"
37 AliveURL = "/ric/v1/health/alive"
38 ConfigURL = "/ric/v1/cm/{name}"
39 AppConfigURL = "/ric/v1/config"
46 type StatusCb func() bool
53 func NewRouter() *Router {
55 router: mux.NewRouter().StrictSlash(true),
56 cbMap: make([]StatusCb, 0),
59 // Inject default routes for health probes
60 r.InjectRoute(ReadyURL, readyHandler, "GET")
61 r.InjectRoute(AliveURL, aliveHandler, "GET")
62 r.InjectRoute(ConfigURL, configHandler, "POST")
63 r.InjectRoute(AppConfigURL, appconfigHandler, "GET")
68 func (r *Router) serviceChecker(inner http.HandlerFunc) http.HandlerFunc {
69 return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
70 Logger.Info("restapi: method=%s url=%s", req.Method, req.URL.RequestURI())
71 if req.URL.RequestURI() == AliveURL || r.CheckStatus() {
72 inner.ServeHTTP(w, req)
74 respondWithJSON(w, http.StatusServiceUnavailable, nil)
79 func (r *Router) InjectRoute(url string, handler http.HandlerFunc, method string) *mux.Route {
80 return r.router.Path(url).HandlerFunc(r.serviceChecker(handler)).Methods(method)
83 func (r *Router) InjectQueryRoute(url string, h http.HandlerFunc, m string, q ...string) *mux.Route {
84 return r.router.Path(url).HandlerFunc(r.serviceChecker(h)).Methods(m).Queries(q...)
87 func (r *Router) InjectRoutePrefix(prefix string, handler http.HandlerFunc) *mux.Route {
88 return r.router.PathPrefix(prefix).HandlerFunc(r.serviceChecker(handler))
91 func (r *Router) InjectStatusCb(f StatusCb) {
92 r.cbMap = append(r.cbMap, f)
95 func (r *Router) CheckStatus() (status bool) {
96 if len(r.cbMap) == 0 {
100 for _, f := range r.cbMap {
106 func (r *Router) GetSymptomDataParams(w http.ResponseWriter, req *http.Request) SymptomDataParams {
107 Logger.Info("GetSymptomDataParams ...")
109 params := SymptomDataParams{}
110 queryParams := req.URL.Query()
112 Logger.Info("GetSymptomDataParams: %+v", queryParams)
114 for p := range queryParams {
116 fmt.Sscanf(p, "%d", ¶ms.Timeout)
119 fmt.Sscanf(p, "%d", ¶ms.FromTime)
122 fmt.Sscanf(p, "%d", ¶ms.ToTime)
128 func (r *Router) CollectDefaultSymptomData(fileName string, data interface{}) string {
129 baseDir := Config.GetString("controls.symptomdata.baseDir")
131 baseDir = "/tmp/xapp/"
134 if err := Util.CreateDir(baseDir); err != nil {
135 Logger.Error("CreateDir failed: %v", err)
139 if metrics, err := r.GetLocalMetrics(GetPortData("http").Port); err == nil {
140 if err := Util.WriteToFile(baseDir+"metrics.json", metrics); err != nil {
141 Logger.Error("writeToFile failed for metrics.json: %v", err)
146 if b, err := json.MarshalIndent(data, "", " "); err == nil {
147 Util.WriteToFile(baseDir+fileName, string(b))
151 rtPath := os.Getenv("RMR_STASH_RT")
156 input, err := ioutil.ReadFile(rtPath)
158 Logger.Error("ioutil.ReadFile failed: %v", err)
162 Util.WriteToFile(baseDir+"rttable.txt", string(input))
166 func (r *Router) SendSymptomDataJson(w http.ResponseWriter, req *http.Request, data interface{}, n string) {
167 w.Header().Set("Content-Type", "application/json")
168 w.Header().Set("Content-Disposition", "attachment; filename="+n)
169 w.WriteHeader(http.StatusOK)
171 response, _ := json.MarshalIndent(data, "", " ")
176 func (r *Router) SendSymptomDataFile(w http.ResponseWriter, req *http.Request, baseDir, zipFile string) {
177 // Compress and reply with attachment
178 tmpFile, err := ioutil.TempFile("", "symptom")
180 r.SendSymptomDataError(w, req, "Failed to create a tmp file: "+err.Error())
183 defer os.Remove(tmpFile.Name())
185 var fileList []string
186 fileList = Util.FetchFiles(baseDir, fileList)
187 err = Util.ZipFiles(tmpFile, baseDir, fileList)
189 r.SendSymptomDataError(w, req, "Failed to zip the files: "+err.Error())
193 w.Header().Set("Content-Disposition", "attachment; filename="+zipFile)
194 http.ServeFile(w, req, tmpFile.Name())
197 func (r *Router) SendSymptomDataError(w http.ResponseWriter, req *http.Request, message string) {
198 w.Header().Set("Content-Disposition", "attachment; filename=error_status.txt")
199 http.Error(w, message, http.StatusInternalServerError)
202 func (r *Router) GetLocalMetrics(port int) (string, error) {
203 resp, err := http.Get(fmt.Sprintf("http://localhost:%d/ric/v1/metrics", port))
207 defer resp.Body.Close()
209 metrics, err := ioutil.ReadAll(resp.Body)
214 return string(metrics), nil
217 func IsHealthProbeReady() bool {
221 func readyHandler(w http.ResponseWriter, r *http.Request) {
223 respondWithJSON(w, http.StatusOK, nil)
226 func aliveHandler(w http.ResponseWriter, r *http.Request) {
227 respondWithJSON(w, http.StatusOK, nil)
230 func configHandler(w http.ResponseWriter, r *http.Request) {
231 xappName := mux.Vars(r)["name"]
232 if xappName == "" || r.Body == nil {
233 respondWithJSON(w, http.StatusBadRequest, nil)
238 body, err := ioutil.ReadAll(r.Body)
240 Logger.Error("ioutil.ReadAll failed: %v", err)
241 respondWithJSON(w, http.StatusInternalServerError, nil)
245 if err := PublishConfigChange(xappName, string(body)); err != nil {
246 respondWithJSON(w, http.StatusInternalServerError, nil)
250 respondWithJSON(w, http.StatusOK, nil)
253 func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
254 w.Header().Set("Content-Type", "application/json")
257 response, _ := json.Marshal(payload)
262 func appconfigHandler(w http.ResponseWriter, r *http.Request) {
264 Logger.Info("Inside appconfigHandler")
266 var appconfig models.XappConfigList
267 var metadata models.ConfigMetadata
268 var xappconfig models.XAppConfig
269 name := viper.GetString("name")
271 metadata.XappName = &name
272 metadata.ConfigType = &configtype
274 configFile, err := os.Open("/opt/ric/config/config-file.json")
276 Logger.Error("Cannot open config file: %v", err)
277 respondWithJSON(w, http.StatusInternalServerError, nil)
278 // return nil,errors.New("Could Not parse the config file")
281 body, err := ioutil.ReadAll(configFile)
283 defer configFile.Close()
285 xappconfig.Metadata = &metadata
286 xappconfig.Config = string(body)
288 appconfig = append(appconfig, &xappconfig)
290 respondWithJSON(w, http.StatusOK, appconfig)
292 //return appconfig,nil