Support for time-to-live
[ric-plt/alarm-go.git] / alarm / alarm.go
index 2246abe..f8d909a 100755 (executable)
 package alarm
 
 import (
+       "bytes"
        "encoding/json"
        "errors"
        "fmt"
+       "io/ioutil"
        "log"
-       "sync"
+       "net/http"
+       "os"
        "time"
        "unsafe"
 )
 
 /*
 #cgo CFLAGS: -I../
-#cgo LDFLAGS: -lrmr_nng -lnng
+#cgo LDFLAGS: -lrmr_si
 
 #include "utils.h"
 */
 import "C"
 
-// Severity for alarms
-type Severity string
-
-// Possible values for Severity
-const (
-       SeverityUnspecified Severity = "UNSPECIFIED"
-       SeverityCritical    Severity = "CRITICAL"
-       SeverityMajor       Severity = "MAJOR"
-       SeverityMinor       Severity = "MINOR"
-       SeverityWarning     Severity = "WARNING"
-       SeverityNormal      Severity = "CLEARED"
-       SeverityDefault     Severity = "DEFAULT"
-)
-
-// Alarm object - see README for more information
-type Alarm struct {
-       ManagedObjectId   string   `json:"managedObjectId"`
-       ApplicationId     string   `json:"applicationId"`
-       SpecificProblem   int      `json:"specificProblem"`
-       PerceivedSeverity Severity `json:"perceivedSeverity"`
-       AdditionalInfo    string   `json:"additionalInfo"`
-       IdentifyingInfo   string   `json:"identifyingInfo"`
-}
-
-// Alarm actions
-type AlarmAction string
-
-// Possible values for alarm actions
-const (
-       AlarmActionRaise    AlarmAction = "RAISE"
-       AlarmActionClear    AlarmAction = "CLEAR"
-       AlarmActionReraise  AlarmAction = "RERAISE"
-       AlarmActionClearAll AlarmAction = "CLEARALL"
-)
-
-type AlarmMessage struct {
-       Alarm
-       AlarmAction
-       AlarmTime int64
-}
-
-// RICAlarm is an alarm instance
-type RICAlarm struct {
-       moId   string
-       appId  string
-       rmrCtx unsafe.Pointer
-       mutex  sync.Mutex
-}
-
 // InitAlarm is the init routine which returns a new alarm instance.
 // The MO and APP identities are given as a parameters.
 // The identities are used when raising/clearing alarms, unless provided by the applications.
 func InitAlarm(mo, id string) (*RICAlarm, error) {
-       if ctx := C.rmrInit(); ctx != nil {
-               r := &RICAlarm{
-                       moId:   mo,
-                       appId:  id,
-                       rmrCtx: ctx,
-               }
+       r := &RICAlarm{
+               moId:       mo,
+               appId:      id,
+               managerUrl: ALARM_MANAGER_HTTP_URL,
+       }
+
+       if os.Getenv("ALARM_MANAGER_URL") != "" {
+               r.managerUrl = os.Getenv("ALARM_MANAGER_URL")
+       }
 
-               return r, nil
+       if os.Getenv("ALARM_IF_RMR") == "" {
+               go InitRMR(r, "")
+       } else {
+               go InitRMR(r, ALARM_MANAGER_RMR_URL)
        }
 
-       return nil, errors.New("rmrInit failed!")
+       return r, nil
 }
 
 // Create a new Alarm instance
@@ -118,17 +78,25 @@ func (r *RICAlarm) NewAlarm(sp int, severity Severity, ainfo, iinfo string) Alar
 
 // Create a new AlarmMessage instance
 func (r *RICAlarm) NewAlarmMessage(a Alarm, alarmAction AlarmAction) AlarmMessage {
-       alarmTime := time.Now().UnixNano() / 1000
+       alarmTime := time.Now().UnixNano()
        return AlarmMessage{a, alarmAction, alarmTime}
 }
 
+func (r *RICAlarm) SetManagedObjectId(mo string) {
+       r.moId = mo
+}
+
+func (r *RICAlarm) SetApplicationId(app string) {
+       r.appId = app
+}
+
 // Raise a RIC alarm
 func (r *RICAlarm) Raise(a Alarm) error {
        r.mutex.Lock()
        defer r.mutex.Unlock()
 
        m := r.NewAlarmMessage(a, AlarmActionRaise)
-       return r.SendMessage(m)
+       return r.sendAlarmUpdateReq(m)
 }
 
 // Clear a RIC alarm
@@ -137,7 +105,7 @@ func (r *RICAlarm) Clear(a Alarm) error {
        defer r.mutex.Unlock()
 
        m := r.NewAlarmMessage(a, AlarmActionClear)
-       return r.SendMessage(m)
+       return r.sendAlarmUpdateReq(m)
 }
 
 // Re-raise a RIC alarm
@@ -145,8 +113,12 @@ func (r *RICAlarm) Reraise(a Alarm) error {
        r.mutex.Lock()
        defer r.mutex.Unlock()
 
-       m := r.NewAlarmMessage(a, AlarmActionReraise)
-       return r.SendMessage(m)
+       m := r.NewAlarmMessage(a, AlarmActionClear)
+       if err := r.sendAlarmUpdateReq(m); err != nil {
+               return errors.New(fmt.Sprintf("Reraise failed: %v", err))
+       }
+
+       return r.sendAlarmUpdateReq(r.NewAlarmMessage(a, AlarmActionRaise))
 }
 
 // Clear all alarms raised by the application
@@ -157,31 +129,43 @@ func (r *RICAlarm) ClearAll() error {
        a := r.NewAlarm(0, SeverityDefault, "", "")
        m := r.NewAlarmMessage(a, AlarmActionClearAll)
 
-       return r.SendMessage(m)
+       return r.sendAlarmUpdateReq(m)
 }
 
-// Internal functions
 func (r *RICAlarm) AlarmString(a AlarmMessage) string {
        s := "MOId=%s AppId=%s SP=%d severity=%s IA=%s"
        return fmt.Sprintf(s, a.ManagedObjectId, a.ApplicationId, a.SpecificProblem, a.PerceivedSeverity, a.IdentifyingInfo)
 }
 
-func (r *RICAlarm) SendMessage(a AlarmMessage) error {
-       log.Println("Sending alarm:", r.AlarmString(a))
+func (r *RICAlarm) sendAlarmUpdateReq(a AlarmMessage) error {
 
        payload, err := json.Marshal(a)
        if err != nil {
+               log.Println("json.Marshal failed with error: ", err)
                return err
        }
+       log.Println("Sending alarm: ", fmt.Sprintf("%s", payload))
+
+       if r.rmrCtx == nil || !r.rmrReady {
+               url := fmt.Sprintf("%s/%s", r.managerUrl, "ric/v1/alarms")
+               resp, err := http.Post(url, "application/json", bytes.NewReader(payload))
+               if err != nil || resp == nil {
+                       return fmt.Errorf("Unable to send alarm: %v", err)
+               }
+               log.Printf("Alarm posted to %s [status=%d]", url, resp.StatusCode)
+               return nil
+       }
 
        datap := C.CBytes(payload)
        defer C.free(datap)
        meid := C.CString("ric")
        defer C.free(unsafe.Pointer(meid))
 
-       if state := C.rmrSend(r.rmrCtx, 1234, datap, C.int(len(payload)), meid); state != C.RMR_OK {
+       if state := C.rmrSend(r.rmrCtx, RIC_ALARM_UPDATE, datap, C.int(len(payload)), meid); state != C.RMR_OK {
+               log.Println("rmrSend failed with error: ", state)
                return errors.New(fmt.Sprintf("rmrSend failed with error: %d", state))
        }
+
        return nil
 }
 
@@ -195,3 +179,37 @@ func (r *RICAlarm) ReceiveMessage(cb func(AlarmMessage)) error {
        }
        return errors.New("rmrRcv failed!")
 }
+
+func InitRMR(r *RICAlarm, endpoint string) error {
+       // Setup static RT for alarm system
+       if endpoint == "" {
+               if r.moId == "my-pod" {
+                       endpoint = "127.0.0.1:4560"
+               } else if r.moId == "my-pod-lib" {
+                       endpoint = "127.0.0.1:4588"
+               }
+       }
+
+       alarmRT := fmt.Sprintf("newrt|start\nrte|13111|%s\nnewrt|end\n", endpoint)
+       alarmRTFile := "/tmp/alarm.rt"
+
+       if err := ioutil.WriteFile(alarmRTFile, []byte(alarmRT), 0644); err != nil {
+               log.Println("ioutil.WriteFile failed with error: ", err)
+               return err
+       }
+
+       os.Setenv("RMR_SEED_RT", alarmRTFile)
+       os.Setenv("RMR_RTG_SVC", "-1")
+
+       if ctx := C.rmrInit(); ctx != nil {
+               r.rmrCtx = ctx
+               r.rmrReady = true
+               return nil
+       }
+
+       return errors.New("rmrInit failed!")
+}
+
+func (r *RICAlarm) IsRMRReady() bool {
+       return r.rmrReady
+}