Initial alarm adapter implementation
[ric-plt/alarm-go.git] / alarm / alarm.go
1 /*
2  *  Copyright (c) 2020 AT&T Intellectual Property.
3  *  Copyright (c) 2020 Nokia.
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  * This source code is part of the near-RT RIC (RAN Intelligent Controller)
18  * platform project (RICP).
19  */
20
21 package alarm
22
23 import (
24         "encoding/json"
25         "errors"
26         "fmt"
27         "log"
28         "sync"
29         "time"
30         "unsafe"
31 )
32
33 /*
34 #cgo CFLAGS: -I../
35 #cgo LDFLAGS: -lrmr_nng -lnng
36
37 #include "utils.h"
38 */
39 import "C"
40
41 // Severity for alarms
42 type Severity string
43
44 // Possible values for Severity
45 const (
46         SeverityUnspecified Severity = "UNSPECIFIED"
47         SeverityCritical    Severity = "CRITICAL"
48         SeverityMajor       Severity = "MAJOR"
49         SeverityMinor       Severity = "MINOR"
50         SeverityWarning     Severity = "WARNING"
51         SeverityCleared     Severity = "CLEARED"
52         SeverityDefault     Severity = "DEFAULT"
53 )
54
55 // Alarm object - see README for more information
56 type Alarm struct {
57         ManagedObjectId   string   `json:"managedObjectId"`
58         ApplicationId     string   `json:"applicationId"`
59         SpecificProblem   int      `json:"specificProblem"`
60         PerceivedSeverity Severity `json:"perceivedSeverity"`
61         AdditionalInfo    string   `json:"additionalInfo"`
62         IdentifyingInfo   string   `json:"identifyingInfo"`
63 }
64
65 // Alarm actions
66 type AlarmAction string
67
68 // Possible values for alarm actions
69 const (
70         AlarmActionRaise    AlarmAction = "RAISE"
71         AlarmActionClear    AlarmAction = "CLEAR"
72         AlarmActionClearAll AlarmAction = "CLEARALL"
73 )
74
75 type AlarmMessage struct {
76         Alarm
77         AlarmAction
78         AlarmTime int64
79 }
80
81 // RICAlarm is an alarm instance
82 type RICAlarm struct {
83         moId   string
84         appId  string
85         rmrCtx unsafe.Pointer
86         mutex  sync.Mutex
87 }
88
89 const (
90         RIC_ALARM_UPDATE = 13111
91         RIC_ALARM_QUERY  = 13112
92 )
93
94 // InitAlarm is the init routine which returns a new alarm instance.
95 // The MO and APP identities are given as a parameters.
96 // The identities are used when raising/clearing alarms, unless provided by the applications.
97 func InitAlarm(mo, id string) (*RICAlarm, error) {
98         if ctx := C.rmrInit(); ctx != nil {
99                 r := &RICAlarm{
100                         moId:   mo,
101                         appId:  id,
102                         rmrCtx: ctx,
103                 }
104
105                 return r, nil
106         }
107
108         return nil, errors.New("rmrInit failed!")
109 }
110
111 // Create a new Alarm instance
112 func (r *RICAlarm) NewAlarm(sp int, severity Severity, ainfo, iinfo string) Alarm {
113         return Alarm{
114                 ManagedObjectId:   r.moId,
115                 ApplicationId:     r.appId,
116                 SpecificProblem:   sp,
117                 PerceivedSeverity: severity,
118                 AdditionalInfo:    ainfo,
119                 IdentifyingInfo:   iinfo,
120         }
121 }
122
123 // Create a new AlarmMessage instance
124 func (r *RICAlarm) NewAlarmMessage(a Alarm, alarmAction AlarmAction) AlarmMessage {
125         alarmTime := time.Now().UnixNano() / 1000
126         return AlarmMessage{a, alarmAction, alarmTime}
127 }
128
129 // Raise a RIC alarm
130 func (r *RICAlarm) Raise(a Alarm) error {
131         r.mutex.Lock()
132         defer r.mutex.Unlock()
133
134         m := r.NewAlarmMessage(a, AlarmActionRaise)
135         return r.sendAlarmUpdateReq(m)
136 }
137
138 // Clear a RIC alarm
139 func (r *RICAlarm) Clear(a Alarm) error {
140         r.mutex.Lock()
141         defer r.mutex.Unlock()
142
143         m := r.NewAlarmMessage(a, AlarmActionClear)
144         return r.sendAlarmUpdateReq(m)
145 }
146
147 // Re-raise a RIC alarm
148 func (r *RICAlarm) Reraise(a Alarm) error {
149         r.mutex.Lock()
150         defer r.mutex.Unlock()
151
152         m := r.NewAlarmMessage(a, AlarmActionClear)
153         if err := r.sendAlarmUpdateReq(m); err != nil {
154                 return errors.New(fmt.Sprintf("Reraise failed: %v", err))
155         }
156
157         return r.sendAlarmUpdateReq(r.NewAlarmMessage(a, AlarmActionRaise))
158 }
159
160 // Clear all alarms raised by the application
161 func (r *RICAlarm) ClearAll() error {
162         r.mutex.Lock()
163         defer r.mutex.Unlock()
164
165         a := r.NewAlarm(0, SeverityDefault, "", "")
166         m := r.NewAlarmMessage(a, AlarmActionClearAll)
167
168         return r.sendAlarmUpdateReq(m)
169 }
170
171 func (r *RICAlarm) AlarmString(a AlarmMessage) string {
172         s := "MOId=%s AppId=%s SP=%d severity=%s IA=%s"
173         return fmt.Sprintf(s, a.ManagedObjectId, a.ApplicationId, a.SpecificProblem, a.PerceivedSeverity, a.IdentifyingInfo)
174 }
175
176 func (r *RICAlarm) sendAlarmUpdateReq(a AlarmMessage) error {
177         log.Println("Sending alarm: ", r.AlarmString(a))
178
179         payload, err := json.Marshal(a)
180         if err != nil {
181                 return err
182         }
183
184         datap := C.CBytes(payload)
185         defer C.free(datap)
186         meid := C.CString("ric")
187         defer C.free(unsafe.Pointer(meid))
188
189         if state := C.rmrSend(r.rmrCtx, RIC_ALARM_UPDATE, datap, C.int(len(payload)), meid); state != C.RMR_OK {
190                 log.Println("rmrSend failed with error: ", state)
191                 return errors.New(fmt.Sprintf("rmrSend failed with error: %d", state))
192         }
193         return nil
194 }
195
196 func (r *RICAlarm) ReceiveMessage(cb func(AlarmMessage)) error {
197         if rbuf := C.rmrRcv(r.rmrCtx); rbuf != nil {
198                 payload := C.GoBytes(unsafe.Pointer(rbuf.payload), C.int(rbuf.len))
199                 a := AlarmMessage{}
200                 if err := json.Unmarshal(payload, &a); err == nil {
201                         cb(a)
202                 }
203         }
204         return errors.New("rmrRcv failed!")
205 }