From 2a74ea585d058fad21875877daf58ac018c808d4 Mon Sep 17 00:00:00 2001 From: Mohamed Abukar Date: Sun, 7 Mar 2021 10:10:58 +0200 Subject: [PATCH] Providing symptom data for alarms Change-Id: I39ea5f0a192cd25e86d5e9e83ca05b6372e7a92a Signed-off-by: Mohamed Abukar --- config/config-file.json | 2 +- manager/cmd/manager.go | 2 +- manager/cmd/manager_test.go | 1 - manager/cmd/restapi.go | 50 ++++++++++++ manager/cmd/types.go | 1 + manager/cmd/utils.go | 193 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 246 insertions(+), 3 deletions(-) create mode 100755 manager/cmd/utils.go diff --git a/config/config-file.json b/config/config-file.json index 06f1e92..267f1bd 100755 --- a/config/config-file.json +++ b/config/config-file.json @@ -1,6 +1,6 @@ { "local": { - "host": ":8080" + "host": ":8099" }, "logger": { "level": 4 diff --git a/manager/cmd/manager.go b/manager/cmd/manager.go index 88d90cf..c1f1a66 100755 --- a/manager/cmd/manager.go +++ b/manager/cmd/manager.go @@ -386,7 +386,7 @@ func (a *AlarmManager) ConfigChangeCB(configparam string) { if a.maxAlarmHistory == 0 { a.maxAlarmHistory = 20000 } - + a.alertInterval = viper.GetInt("controls.promAlertManager.alertInterval") a.amHost = viper.GetString("controls.promAlertManager.address") diff --git a/manager/cmd/manager_test.go b/manager/cmd/manager_test.go index 0e2cef4..5f1cecc 100755 --- a/manager/cmd/manager_test.go +++ b/manager/cmd/manager_test.go @@ -723,4 +723,3 @@ func readJSONFromFile(filename string) ([]byte, error) { } return file, nil } - diff --git a/manager/cmd/restapi.go b/manager/cmd/restapi.go index b8062a0..7d2a55c 100755 --- a/manager/cmd/restapi.go +++ b/manager/cmd/restapi.go @@ -41,6 +41,10 @@ func (a *AlarmManager) InjectRoutes() { app.Resource.InjectRoute("/ric/v1/alarms/define/{alarmId}", a.DeleteAlarmDefinition, "DELETE") app.Resource.InjectRoute("/ric/v1/alarms/define", a.GetAlarmDefinition, "GET") app.Resource.InjectRoute("/ric/v1/alarms/define/{alarmId}", a.GetAlarmDefinition, "GET") + + app.Resource.InjectRoute("/ric/v1/symptomdata", a.SymptomDataHandler, "GET") + + a.utils = NewUtils() } func (a *AlarmManager) respondWithError(w http.ResponseWriter, code int, message string) { @@ -239,3 +243,49 @@ func (a *AlarmManager) GetAlarmConfig(w http.ResponseWriter, r *http.Request) { a.respondWithJSON(w, http.StatusOK, m) return } + +func (a *AlarmManager) SymptomDataHandler(w http.ResponseWriter, r *http.Request) { + baseDir := "/tmp/symptomdata/" + if err := a.utils.CreateDir(baseDir); err != nil { + a.utils.SendSymptomDataError(w, r, "CreateDir failed: "+err.Error()) + return + } + + if b, err := json.Marshal(a.activeAlarms); err == nil { + if err := a.utils.WriteToFile(baseDir+"active_alarms.json", string(b)); err != nil { + a.utils.SendSymptomDataError(w, r, "writeToFile failed: "+err.Error()) + return + } + } + + if b, err := json.Marshal(a.alarmHistory); err == nil { + if err := a.utils.WriteToFile(baseDir+"alarm_history.json", string(b)); err != nil { + a.utils.SendSymptomDataError(w, r, "writeToFile failed: "+err.Error()) + return + } + } + + var ac alarm.AlarmConfigParams + ac.MaxActiveAlarms = a.maxActiveAlarms + ac.MaxAlarmHistory = a.maxAlarmHistory + + if b, err := json.Marshal(ac); err == nil { + if err := a.utils.WriteToFile(baseDir+"alarm_config.json", string(b)); err != nil { + a.utils.SendSymptomDataError(w, r, "writeToFile failed: "+err.Error()) + return + } + } + + var ad RicAlarmDefinitions + for _, alarmDefinition := range alarm.RICAlarmDefinitions { + ad.AlarmDefinitions = append(ad.AlarmDefinitions, alarmDefinition) + } + if b, err := json.Marshal(ad); err == nil { + if err := a.utils.WriteToFile(baseDir+"alarm_defs.json", string(b)); err != nil { + a.utils.SendSymptomDataError(w, r, "writeToFile failed: "+err.Error()) + return + } + } + + a.utils.SendSymptomDataFile(w, r, baseDir, "symptomdata.zip") +} diff --git a/manager/cmd/types.go b/manager/cmd/types.go index 27376e9..1b5aaed 100755 --- a/manager/cmd/types.go +++ b/manager/cmd/types.go @@ -43,6 +43,7 @@ type AlarmManager struct { exceededActiveAlarmOn bool exceededAlarmHistoryOn bool alarmInfoPvFile string + utils *Utils } type AlarmNotification struct { diff --git a/manager/cmd/utils.go b/manager/cmd/utils.go new file mode 100755 index 0000000..5977f58 --- /dev/null +++ b/manager/cmd/utils.go @@ -0,0 +1,193 @@ +/* +================================================================================== + Copyright (c) 2019 AT&T Intellectual Property. + Copyright (c) 2019 Nokia + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +================================================================================== +*/ + +package main + +import ( + "archive/zip" + "encoding/json" + "io" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "strings" + + app "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp" +) + +type Utils struct { + baseDir string + status string +} + +func NewUtils() *Utils { + b := app.Config.GetString("controls.symptomdata.baseDir") + if b == "" { + b = "/tmp/symptomdata/" + } + + return &Utils{ + baseDir: b, + } +} + +func (u *Utils) FileExists(f string) bool { + _, err := os.Stat(f) + return err == nil || os.IsExist(err) +} + +func (u *Utils) CreateDir(path string) error { + if u.FileExists(path) { + os.RemoveAll(path) + } + err := os.MkdirAll(path, os.ModePerm) + if err != nil { + return err + } + os.Chmod(path, os.ModePerm) + return nil +} + +func (u *Utils) DeleteFile(fileName string) { + os.Remove(fileName) +} + +func (u *Utils) AddFileToZip(zipWriter *zip.Writer, filePath string, filename string) error { + fileToZip, err := os.Open(filename) + if err != nil { + return err + } + defer fileToZip.Close() + + info, err := fileToZip.Stat() + if err != nil { + return err + } + + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + + if strings.HasPrefix(filename, filePath) { + filename = strings.TrimPrefix(filename, filePath) + } + header.Name = filename + header.Method = zip.Deflate + + writer, err := zipWriter.CreateHeader(header) + if err != nil { + return err + } + if info.Size() > 0 { + _, err = io.Copy(writer, fileToZip) + } + return err +} + +func (u *Utils) ZipFiles(newZipFile *os.File, filePath string, files []string) error { + defer newZipFile.Close() + zipWriter := zip.NewWriter(newZipFile) + defer zipWriter.Close() + for _, file := range files { + if err := u.AddFileToZip(zipWriter, filePath, file); err != nil { + app.Logger.Error("AddFileToZip() failed: %+v", err.Error()) + return err + } + } + + return nil +} + +func (u *Utils) FetchFiles(filePath string, fileList []string) []string { + files, err := ioutil.ReadDir(filePath) + if err != nil { + app.Logger.Error("ioutil.ReadDir failed: %+v", err) + return nil + } + for _, file := range files { + if !file.IsDir() { + fileList = append(fileList, filepath.Join(filePath, file.Name())) + } else { + subPath := filepath.Join(filePath, file.Name()) + subFiles, _ := ioutil.ReadDir(subPath) + for _, subFile := range subFiles { + if !subFile.IsDir() { + fileList = append(fileList, filepath.Join(subPath, subFile.Name())) + } else { + fileList = u.FetchFiles(filepath.Join(subPath, subFile.Name()), fileList) + } + } + } + } + return fileList +} + +func (u *Utils) WriteToFile(fileName string, data string) error { + f, err := os.Create(fileName) + defer f.Close() + + if err != nil { + app.Logger.Error("Unable to create file %s': %+v", fileName, err) + } else { + _, err := io.WriteString(f, data) + if err != nil { + app.Logger.Error("Unable to write to file '%s': %+v", fileName, err) + u.DeleteFile(fileName) + } + } + return err +} + +func (u *Utils) SendSymptomDataJson(w http.ResponseWriter, req *http.Request, data interface{}, n string) { + w.Header().Set("Content-Type", "application/json") + w.Header().Set("Content-Disposition", "attachment; filename="+n) + w.WriteHeader(http.StatusOK) + if data != nil { + response, _ := json.Marshal(data) + w.Write(response) + } +} + +func (u *Utils) SendSymptomDataFile(w http.ResponseWriter, req *http.Request, baseDir, zipFile string) { + // Compress and reply with attachment + tmpFile, err := ioutil.TempFile("", "symptom") + if err != nil { + u.SendSymptomDataError(w, req, "Failed to create a tmp file: "+err.Error()) + return + } + defer os.Remove(tmpFile.Name()) + + var fileList []string + fileList = u.FetchFiles(baseDir, fileList) + err = u.ZipFiles(tmpFile, baseDir, fileList) + if err != nil { + u.SendSymptomDataError(w, req, "Failed to zip the files: "+err.Error()) + return + } + + w.Header().Set("Content-Disposition", "attachment; filename="+zipFile) + http.ServeFile(w, req, tmpFile.Name()) +} + +func (u *Utils) SendSymptomDataError(w http.ResponseWriter, req *http.Request, message string) { + w.Header().Set("Content-Disposition", "attachment; filename=error_status.txt") + http.Error(w, message, http.StatusInternalServerError) +} -- 2.16.6