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 ==================================================================================
31 "github.com/gorilla/mux"
32 "github.com/spf13/viper"
34 "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/models"
38 ReadyURL = "/ric/v1/health/ready"
39 AliveURL = "/ric/v1/health/alive"
40 ConfigURL = "/ric/v1/cm/{name}"
41 AppConfigURL = "/ric/v1/config"
48 type StatusCb func() bool
55 func NewRouter() *Router {
57 router: mux.NewRouter().StrictSlash(true),
58 cbMap: make([]StatusCb, 0),
61 // Inject default routes for health probes
62 r.InjectRoute(ReadyURL, readyHandler, "GET")
63 r.InjectRoute(AliveURL, aliveHandler, "GET")
64 r.InjectRoute(ConfigURL, configHandler, "POST")
65 r.InjectRoute(AppConfigURL, appconfigHandler, "GET")
70 func (r *Router) serviceChecker(inner http.HandlerFunc) http.HandlerFunc {
71 return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
72 Logger.Debug("restapi: method=%s url=%s", req.Method, req.URL.RequestURI())
73 if req.URL.RequestURI() == AliveURL || r.CheckStatus() {
74 inner.ServeHTTP(w, req)
76 respondWithJSON(w, http.StatusServiceUnavailable, nil)
81 func (r *Router) InjectRoute(url string, handler http.HandlerFunc, method string) *mux.Route {
82 return r.router.Path(url).HandlerFunc(r.serviceChecker(handler)).Methods(method)
85 func (r *Router) InjectQueryRoute(url string, h http.HandlerFunc, m string, q ...string) *mux.Route {
86 return r.router.Path(url).HandlerFunc(r.serviceChecker(h)).Methods(m).Queries(q...)
89 func (r *Router) InjectRoutePrefix(prefix string, handler http.HandlerFunc) *mux.Route {
90 return r.router.PathPrefix(prefix).HandlerFunc(r.serviceChecker(handler))
93 func (r *Router) InjectStatusCb(f StatusCb) {
94 r.cbMap = append(r.cbMap, f)
97 func (r *Router) CheckStatus() (status bool) {
98 if len(r.cbMap) == 0 {
102 for _, f := range r.cbMap {
108 func (r *Router) GetSymptomDataParams(w http.ResponseWriter, req *http.Request) SymptomDataParams {
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)
140 if metrics, err := r.GetLocalMetrics(GetPortData("http").Port); err == nil {
141 if err := Util.WriteToFile(baseDir+"metrics.json", metrics); err != nil {
142 Logger.Error("writeToFile failed for metrics.json: %v", err)
148 if b, err := json.MarshalIndent(data, "", " "); err == nil {
149 Util.WriteToFile(baseDir+fileName, string(b))
154 cfile := viper.ConfigFileUsed()
155 input, err := ioutil.ReadFile(cfile)
157 Util.WriteToFile(baseDir+path.Base(cfile), string(input))
159 Logger.Error("ioutil.ReadFile failed: %v", err)
163 Util.WriteToFile(baseDir+"environment", strings.Join(os.Environ(), "\n"))
166 rtPath := os.Getenv("RMR_STASH_RT")
168 input, err = ioutil.ReadFile(rtPath)
170 Util.WriteToFile(baseDir+"rttable.txt", string(input))
172 Logger.Error("ioutil.ReadFile failed: %v", err)
179 func (r *Router) SendSymptomDataJson(w http.ResponseWriter, req *http.Request, data interface{}, n string) {
180 w.Header().Set("Content-Type", "application/json")
181 w.Header().Set("Content-Disposition", "attachment; filename="+n)
182 w.WriteHeader(http.StatusOK)
184 response, _ := json.MarshalIndent(data, "", " ")
189 func (r *Router) SendSymptomDataFile(w http.ResponseWriter, req *http.Request, baseDir, zipFile string) {
191 var fileList []string
192 fileList = Util.FetchFiles(baseDir, fileList)
193 tmpFileName, err := Util.ZipFilesToTmpFile(baseDir, "symptom", fileList)
195 r.SendSymptomDataError(w, req, err.Error())
198 defer os.Remove(tmpFileName)
200 w.Header().Set("Content-Disposition", "attachment; filename="+zipFile)
201 http.ServeFile(w, req, tmpFileName)
204 func (r *Router) SendSymptomDataError(w http.ResponseWriter, req *http.Request, message string) {
205 w.Header().Set("Content-Disposition", "attachment; filename=error_status.txt")
206 http.Error(w, message, http.StatusInternalServerError)
209 func (r *Router) GetLocalMetrics(port int) (string, error) {
210 resp, err := http.Get(fmt.Sprintf("http://localhost:%d/ric/v1/metrics", port))
212 Logger.Error("GetLocalMetrics: http.Get failed: %v", err)
215 defer resp.Body.Close()
217 metrics, err := ioutil.ReadAll(resp.Body)
219 Logger.Error("GetLocalMetrics: ioutil.ReadAll failed: %v", err)
223 return string(metrics), nil
226 func IsHealthProbeReady() bool {
230 func readyHandler(w http.ResponseWriter, r *http.Request) {
232 respondWithJSON(w, http.StatusOK, nil)
235 func aliveHandler(w http.ResponseWriter, r *http.Request) {
236 respondWithJSON(w, http.StatusOK, nil)
239 func configHandler(w http.ResponseWriter, r *http.Request) {
240 xappName := mux.Vars(r)["name"]
241 if xappName == "" || r.Body == nil {
242 respondWithJSON(w, http.StatusBadRequest, nil)
247 body, err := ioutil.ReadAll(r.Body)
249 Logger.Error("ioutil.ReadAll failed: %v", err)
250 respondWithJSON(w, http.StatusInternalServerError, nil)
254 if err := PublishConfigChange(xappName, string(body)); err != nil {
255 respondWithJSON(w, http.StatusInternalServerError, nil)
259 respondWithJSON(w, http.StatusOK, nil)
262 func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
263 w.Header().Set("Content-Type", "application/json")
266 response, _ := json.Marshal(payload)
271 func appconfigHandler(w http.ResponseWriter, r *http.Request) {
273 Logger.Info("Inside appconfigHandler")
275 var appconfig models.XappConfigList
276 var metadata models.ConfigMetadata
277 var xappconfig models.XAppConfig
278 name := viper.GetString("name")
280 metadata.XappName = &name
281 metadata.ConfigType = &configtype
283 configFile, err := os.Open("/opt/ric/config/config-file.json")
285 Logger.Error("Cannot open config file: %v", err)
286 respondWithJSON(w, http.StatusInternalServerError, nil)
287 // return nil,errors.New("Could Not parse the config file")
290 body, err := ioutil.ReadAll(configFile)
292 defer configFile.Close()
294 xappconfig.Metadata = &metadata
295 xappconfig.Config = string(body)
297 appconfig = append(appconfig, &xappconfig)
299 respondWithJSON(w, http.StatusOK, appconfig)
301 //return appconfig,nil