From 0ce03386e6dbdb82b88406b22bb91c8cbe18e349 Mon Sep 17 00:00:00 2001 From: Mohamed Abukar Date: Wed, 24 Feb 2021 10:52:25 +0200 Subject: [PATCH] Add utility module Change-Id: I74b06f0ff44e31f6c7a0a7c6bd9c478012b3f305 Signed-off-by: Mohamed Abukar --- pkg/xapp/Utils.go | 153 ++++++++++++++++++++++++++++++++++++++++++ pkg/xapp/alarm_test.go | 4 +- pkg/xapp/metrics_test.go | 3 +- pkg/xapp/restapi.go | 55 +++++++++++++++ pkg/xapp/subscription_test.go | 4 +- pkg/xapp/types.go | 6 ++ pkg/xapp/xapp.go | 2 + 7 files changed, 221 insertions(+), 6 deletions(-) create mode 100755 pkg/xapp/Utils.go diff --git a/pkg/xapp/Utils.go b/pkg/xapp/Utils.go new file mode 100755 index 0000000..90bc093 --- /dev/null +++ b/pkg/xapp/Utils.go @@ -0,0 +1,153 @@ +/* +================================================================================== + 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 xapp + +import ( + "archive/zip" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" +) + +type Utils struct { + baseDir string + status string +} + +func NewUtils() *Utils { + b := 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 { + 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 { + 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 { + Logger.Error("Unable to create file %s': %+v", fileName, err) + } else { + _, err := io.WriteString(f, data) + if err != nil { + Logger.Error("Unable to write to file '%s': %+v", fileName, err) + u.DeleteFile(fileName) + } + } + return err +} diff --git a/pkg/xapp/alarm_test.go b/pkg/xapp/alarm_test.go index b72c319..f8de8bd 100755 --- a/pkg/xapp/alarm_test.go +++ b/pkg/xapp/alarm_test.go @@ -20,8 +20,8 @@ package xapp import ( - "testing" "github.com/stretchr/testify/assert" + "testing" "gerrit.o-ran-sc.org/r/ric-plt/alarm-go.git/alarm" ) @@ -67,4 +67,4 @@ func TestAlarmClearall(t *testing.T) { assert.NotNil(t, a, "NewAlarmClient failed") a.ClearAll() -} \ No newline at end of file +} diff --git a/pkg/xapp/metrics_test.go b/pkg/xapp/metrics_test.go index e600743..bd7c737 100755 --- a/pkg/xapp/metrics_test.go +++ b/pkg/xapp/metrics_test.go @@ -41,7 +41,7 @@ func TestMetricSetup(t *testing.T) { }, []string{"name", "event"}, "SUBSYSTEM") - + mGGroup = Metric.RegisterGaugeGroup( []CounterOpts{ {Name: "counter3", Help: "counter3"}, @@ -259,4 +259,3 @@ func TestMetricGroupCache(t *testing.T) { m_grp.GDec("event2_counter2") m_grp.GSet("event2_counter2", 1) } - diff --git a/pkg/xapp/restapi.go b/pkg/xapp/restapi.go index e335c08..40ad8d2 100755 --- a/pkg/xapp/restapi.go +++ b/pkg/xapp/restapi.go @@ -21,6 +21,7 @@ package xapp import ( "encoding/json" + "fmt" "github.com/gorilla/mux" "github.com/spf13/viper" "io/ioutil" @@ -101,6 +102,60 @@ func (r *Router) CheckStatus() (status bool) { return } +func (r *Router) GetSymptomDataParams(w http.ResponseWriter, req *http.Request) SymptomDataParams { + params := SymptomDataParams{} + queryParams := req.URL.Query() + + for p := range queryParams { + if p == "timeout" { + fmt.Sscanf(p, "%d", ¶ms.Timeout) + } + if p == "fromtime" { + fmt.Sscanf(p, "%d", ¶ms.FromTime) + } + if p == "totime" { + fmt.Sscanf(p, "%d", ¶ms.ToTime) + } + } + return params +} + +func (r *Router) 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 (r *Router) SendSymptomDataFile(w http.ResponseWriter, req *http.Request, baseDir, zipFile string) { + // Compress and reply with attachment + tmpFile, err := ioutil.TempFile("", "symptom") + if err != nil { + r.SendSymptomDataError(w, req, "Failed to create a tmp file: "+err.Error()) + return + } + defer os.Remove(tmpFile.Name()) + + var fileList []string + fileList = Util.FetchFiles(baseDir, fileList) + err = Util.ZipFiles(tmpFile, baseDir, fileList) + if err != nil { + r.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 (r *Router) 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) +} + func IsHealthProbeReady() bool { return healthReady } diff --git a/pkg/xapp/subscription_test.go b/pkg/xapp/subscription_test.go index d1ea66f..430b0a2 100755 --- a/pkg/xapp/subscription_test.go +++ b/pkg/xapp/subscription_test.go @@ -7,12 +7,12 @@ package xapp import ( + "fmt" "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/clientmodel" "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/models" "github.com/stretchr/testify/assert" "testing" "time" - "fmt" ) var suite *testing.T @@ -59,7 +59,7 @@ func processSubscriptions(subscriptionId string) { resp := &models.SubscriptionResponse{ SubscriptionID: &subscriptionId, SubscriptionInstances: []*models.SubscriptionInstance{ - &models.SubscriptionInstance{RequestorID: &reqId, InstanceID: &instanceId}, + {RequestorID: &reqId, InstanceID: &instanceId}, }, } diff --git a/pkg/xapp/types.go b/pkg/xapp/types.go index c9fe1ec..fa88de7 100755 --- a/pkg/xapp/types.go +++ b/pkg/xapp/types.go @@ -82,6 +82,12 @@ type PortData struct { MaxRetryOnFailure int } +type SymptomDataParams struct { + Timeout uint64 + FromTime uint64 + ToTime uint64 +} + // @todo: read these from config or somewhere else const ( SERVICE_HTTP = "SERVICE_%s_%s_HTTP_PORT" diff --git a/pkg/xapp/xapp.go b/pkg/xapp/xapp.go index 1f02285..de355fb 100755 --- a/pkg/xapp/xapp.go +++ b/pkg/xapp/xapp.go @@ -47,6 +47,7 @@ var ( Config Configurator Subscription *Subscriber Alarm *AlarmClient + Util *Utils readyCb ReadyCB readyCbParams interface{} shutdownCb ShutdownCB @@ -250,6 +251,7 @@ func init() { Subscription = NewSubscriber(viper.GetString("subscription.host"), viper.GetInt("subscription.timeout")) Sdl = NewSDLClient(viper.GetString("controls.db.namespace")) Rnib = NewRNIBClient() + Util = NewUtils() InstallSignalHandler() } -- 2.16.6