A local user interface (CLI) for alarm system 12/4712/2
authorMohamed Abukar <abukar.mohamed@nokia.com>
Thu, 17 Sep 2020 11:47:50 +0000 (14:47 +0300)
committerMohamed Abukar <abukar.mohamed@nokia.com>
Thu, 17 Sep 2020 13:48:46 +0000 (16:48 +0300)
Change-Id: I1d1443456d724316a07021443d13270feadd975c
Signed-off-by: Mohamed Abukar <abukar.mohamed@nokia.com>
adapter/cmd/adapter.go
adapter/cmd/types.go
cli/alarm-cli.go [new file with mode: 0755]
go.mod
go.sum

index f68d424..a3a9050 100755 (executable)
@@ -42,7 +42,7 @@ func (a *AlarmAdapter) StartAlertTimer() {
                a.mutex.Lock()
                for _, m := range a.activeAlarms {
                        app.Logger.Info("Re-raising alarm: %v", m)
-                       a.PostAlert(a.GenerateAlertLabels(m, AlertStatusActive))
+                       a.PostAlert(a.GenerateAlertLabels(m.Alarm, AlertStatusActive))
                }
                a.mutex.Unlock()
        }
@@ -102,7 +102,7 @@ func (a *AlarmAdapter) ProcessAlarm(m *alarm.AlarmMessage) (*alert.PostAlertsOK,
 
        // New alarm -> update active alarms and post to Alert Manager
        if m.AlarmAction == alarm.AlarmActionRaise {
-               a.UpdateAlarmLists(m.Alarm)
+               a.UpdateAlarmLists(m)
                return a.PostAlert(a.GenerateAlertLabels(m.Alarm, AlertStatusActive))
        }
 
@@ -112,15 +112,14 @@ func (a *AlarmAdapter) ProcessAlarm(m *alarm.AlarmMessage) (*alert.PostAlertsOK,
 func (a *AlarmAdapter) IsMatchFound(newAlarm alarm.Alarm) (int, bool) {
        for i, m := range a.activeAlarms {
                if m.ManagedObjectId == newAlarm.ManagedObjectId && m.ApplicationId == newAlarm.ApplicationId &&
-                       m.SpecificProblem == newAlarm.SpecificProblem && m.IdentifyingInfo == newAlarm.IdentifyingInfo &&
-                       m.PerceivedSeverity == newAlarm.PerceivedSeverity {
+                       m.SpecificProblem == newAlarm.SpecificProblem && m.IdentifyingInfo == newAlarm.IdentifyingInfo {
                        return i, true
                }
        }
        return -1, false
 }
 
-func (a *AlarmAdapter) RemoveAlarm(alarms []alarm.Alarm, i int, listName string) []alarm.Alarm {
+func (a *AlarmAdapter) RemoveAlarm(alarms []alarm.AlarmMessage, i int, listName string) []alarm.AlarmMessage {
        a.mutex.Lock()
        defer a.mutex.Unlock()
 
@@ -129,7 +128,7 @@ func (a *AlarmAdapter) RemoveAlarm(alarms []alarm.Alarm, i int, listName string)
        return alarms[:len(alarms)-1]
 }
 
-func (a *AlarmAdapter) UpdateAlarmLists(newAlarm alarm.Alarm) {
+func (a *AlarmAdapter) UpdateAlarmLists(newAlarm *alarm.AlarmMessage) {
        a.mutex.Lock()
        defer a.mutex.Unlock()
 
@@ -143,8 +142,8 @@ func (a *AlarmAdapter) UpdateAlarmLists(newAlarm alarm.Alarm) {
        }
 
        // @todo: For now just keep the alarms (both active and history) in-memory. Use SDL later for persistence
-       a.activeAlarms = append(a.activeAlarms, newAlarm)
-       a.alarmHistory = append(a.alarmHistory, newAlarm)
+       a.activeAlarms = append(a.activeAlarms, *newAlarm)
+       a.alarmHistory = append(a.alarmHistory, *newAlarm)
 }
 
 func (a *AlarmAdapter) GenerateAlertLabels(newAlarm alarm.Alarm, status AlertStatus) (models.LabelSet, models.LabelSet) {
@@ -230,8 +229,8 @@ func NewAlarmAdapter(amHost string, alertInterval int) *AlarmAdapter {
                amBaseUrl:     viper.GetString("controls.promAlertManager.baseUrl"),
                amSchemes:     []string{viper.GetString("controls.promAlertManager.schemes")},
                alertInterval: alertInterval,
-               activeAlarms:  make([]alarm.Alarm, 0),
-               alarmHistory:  make([]alarm.Alarm, 0),
+               activeAlarms:  make([]alarm.AlarmMessage, 0),
+               alarmHistory:  make([]alarm.AlarmMessage, 0),
        }
 }
 
index 14cf421..e98fbf4 100755 (executable)
@@ -31,8 +31,8 @@ type AlarmAdapter struct {
        amBaseUrl     string
        amSchemes     []string
        alertInterval int
-       activeAlarms  []alarm.Alarm
-       alarmHistory  []alarm.Alarm
+       activeAlarms  []alarm.AlarmMessage
+       alarmHistory  []alarm.AlarmMessage
        mutex         sync.Mutex
        rmrReady      bool
        postClear     bool
diff --git a/cli/alarm-cli.go b/cli/alarm-cli.go
new file mode 100755 (executable)
index 0000000..212f8ca
--- /dev/null
@@ -0,0 +1,165 @@
+package main
+
+import (
+       "bytes"
+       "encoding/json"
+       "fmt"
+       "github.com/jedib0t/go-pretty/table"
+       "github.com/thatisuday/commando"
+       "io/ioutil"
+       "net/http"
+       "os"
+       "time"
+
+       "gerrit.o-ran-sc.org/r/ric-plt/alarm-go/alarm"
+)
+
+func main() {
+
+       // configure commando
+       commando.
+               SetExecutableName("alarm-cli").
+               SetVersion("1.0.0").
+               SetDescription("This CLI tool provides management interface to SEP alarm system")
+
+       // Get active alarms
+       commando.
+               Register("active").
+               SetShortDescription("Displays the SEP active alarms").
+               SetDescription("This command displays more information about the SEP active alarms").
+               AddFlag("host", "Alarm manager host address", commando.String, "localhost").
+               AddFlag("port", "Alarm manager host address", commando.String, "8080").
+               SetAction(func(args map[string]commando.ArgValue, flags map[string]commando.FlagValue) {
+                       displayAlarms(getAlarms(flags, "active"), false)
+               })
+
+       // Get alarm history
+       commando.
+               Register("history").
+               SetShortDescription("Displays the SEP alarm history").
+               SetDescription("This command displays more information about the SEP alarm history").
+               AddFlag("host", "Alarm manager host address", commando.String, "localhost").
+               AddFlag("port", "Alarm manager host address", commando.String, "8080").
+               SetAction(func(args map[string]commando.ArgValue, flags map[string]commando.FlagValue) {
+                       displayAlarms(getAlarms(flags, "history"), true)
+               })
+
+       // Raise an alarm
+       commando.
+               Register("raise").
+               SetShortDescription("Raises alarm with given parameters").
+               AddFlag("moid", "Managed object Id", commando.String, nil).
+               AddFlag("apid", "Application Id", commando.String, nil).
+               AddFlag("sp", "Specific problem Id", commando.Int, nil).
+               AddFlag("severity", "Perceived severity", commando.String, nil).
+               AddFlag("iinfo", "Application identifying info", commando.String, nil).
+               AddFlag("aai", "Application additional info", commando.String, "-").
+               AddFlag("host", "Alarm manager host address", commando.String, "localhost").
+               AddFlag("port", "Alarm manager host address", commando.String, "8080").
+               SetAction(func(args map[string]commando.ArgValue, flags map[string]commando.FlagValue) {
+                       postAlarm(flags, readAlarmParams(flags, false), alarm.AlarmActionRaise)
+               })
+
+       // Clear an alarm
+       commando.
+               Register("clear").
+               SetShortDescription("Raises alarm with given parameters").
+               AddFlag("moid", "Managed object Id", commando.String, nil).
+               AddFlag("apid", "Application Id", commando.String, nil).
+               AddFlag("sp", "Specific problem Id", commando.Int, nil).
+               AddFlag("iinfo", "Application identifying info", commando.String, nil).
+               AddFlag("host", "Alarm manager host address", commando.String, "localhost").
+               AddFlag("port", "Alarm manager host address", commando.String, "8080").
+               SetAction(func(args map[string]commando.ArgValue, flags map[string]commando.FlagValue) {
+                       postAlarm(flags, readAlarmParams(flags, true), alarm.AlarmActionClear)
+               })
+
+       // parse command-line arguments
+       commando.Parse(nil)
+}
+
+func readAlarmParams(flags map[string]commando.FlagValue, clear bool) (a alarm.Alarm) {
+       a.ManagedObjectId, _ = flags["moid"].GetString()
+       a.ApplicationId, _ = flags["apid"].GetString()
+       a.SpecificProblem, _ = flags["sp"].GetInt()
+       a.IdentifyingInfo, _ = flags["iinfo"].GetString()
+
+       if !clear {
+               s, _ := flags["severity"].GetString()
+               a.PerceivedSeverity = alarm.Severity(s)
+       }
+
+       if !clear {
+               a.AdditionalInfo, _ = flags["aai"].GetString()
+       }
+
+       return
+}
+
+func getAlarms(flags map[string]commando.FlagValue, action alarm.AlarmAction) (alarms []alarm.AlarmMessage) {
+       host, _ := flags["host"].GetString()
+       port, _ := flags["port"].GetString()
+       targetUrl := fmt.Sprintf("http://%s:%s/ric/v1/alarms/%s", host, port, action)
+       resp, err := http.Get(targetUrl)
+       if err != nil || resp == nil || resp.Body == nil {
+               fmt.Println("Couldn't fetch active alarm list due to error: %v", err)
+               return alarms
+       }
+
+       defer resp.Body.Close()
+
+       body, err := ioutil.ReadAll(resp.Body)
+       if err != nil {
+               fmt.Println("ioutil.ReadAll failed: %v", err)
+               return alarms
+       }
+
+       json.Unmarshal([]byte(body), &alarms)
+       fmt.Println(alarms)
+       return alarms
+}
+
+func postAlarm(flags map[string]commando.FlagValue, a alarm.Alarm, action alarm.AlarmAction) {
+       host, _ := flags["host"].GetString()
+       port, _ := flags["port"].GetString()
+       targetUrl := fmt.Sprintf("http://%s:%s/ric/v1/alarms", host, port)
+
+       m := alarm.AlarmMessage{Alarm: a, AlarmAction: action}
+       jsonData, err := json.Marshal(m)
+       if err != nil {
+               fmt.Println("json.Marshal failed: %v", err)
+               return
+       }
+
+       resp, err := http.Post(targetUrl, "application/json", bytes.NewBuffer(jsonData))
+       if err != nil || resp == nil {
+               fmt.Println("Couldn't fetch active alarm list due to error: %v", err)
+               return
+       }
+}
+
+func displayAlarms(alarms []alarm.AlarmMessage, isHistory bool) {
+       t := table.NewWriter()
+       t.SetOutputMirror(os.Stdout)
+       if isHistory {
+               t.AppendHeader(table.Row{"SP", "MOID", "APPID", "IINFO", "SEVERITY", "AAI", "TIME", "ACTION"})
+       } else {
+               t.AppendHeader(table.Row{"SP", "MOID", "APPID", "IINFO", "SEVERITY", "AAI", "TIME"})
+       }
+
+       for _, a := range alarms {
+               alarmTime := time.Unix(0, a.AlarmTime).Format("02/01/2006, 15:04:05")
+               if isHistory {
+                       t.AppendRows([]table.Row{
+                               {a.SpecificProblem, a.ManagedObjectId, a.ApplicationId, a.IdentifyingInfo, a.PerceivedSeverity, a.AdditionalInfo, alarmTime, a.AlarmAction},
+                       })
+               } else {
+                       t.AppendRows([]table.Row{
+                               {a.SpecificProblem, a.ManagedObjectId, a.ApplicationId, a.IdentifyingInfo, a.PerceivedSeverity, a.AdditionalInfo, alarmTime},
+                       })
+               }
+       }
+
+       t.SetStyle(table.StyleColoredBright)
+       t.Render()
+}
diff --git a/go.mod b/go.mod
index cc1fa1d..23fac57 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -16,9 +16,12 @@ require (
        gerrit.o-ran-sc.org/r/ric-plt/xapp-frame v0.0.0-00010101000000-000000000000
        github.com/go-openapi/runtime v0.19.11
        github.com/go-openapi/strfmt v0.19.4
+       github.com/jedib0t/go-pretty v4.3.0+incompatible // indirect
+       github.com/mattn/go-runewidth v0.0.9 // indirect
        github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
        github.com/modern-go/reflect2 v1.0.1 // indirect
        github.com/prometheus/alertmanager v0.20.0
        github.com/spf13/viper v1.6.2
        github.com/stretchr/testify v1.5.1
+       github.com/thatisuday/commando v1.0.4 // indirect
 )
diff --git a/go.sum b/go.sum
index 8489760..9acf904 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -170,6 +170,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo=
+github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag=
 github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
 github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
@@ -199,6 +201,8 @@ github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM
 github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
@@ -283,6 +287,10 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/thatisuday/clapper v1.0.10 h1:1EkqE/nb4npp8DuTKnpvVzO/Mcac9lOPND34uUKF+bU=
+github.com/thatisuday/clapper v1.0.10/go.mod h1:FQGIg8q2uzeI+3SUS82YKF4E3KexkHStbiK4qTfDknM=
+github.com/thatisuday/commando v1.0.4 h1:aNdH9tvmx2EPG6rT3NTQOV/qFYPf4Ap4Spo+q+n9Ois=
+github.com/thatisuday/commando v1.0.4/go.mod h1:ODGz6jwJs4QqhLJtCjRRs8xIrmLLMdatYYddP+v1b4E=
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=