--- /dev/null
+RIC Alarm Adapter and Library Interface
+=======================================
+
+This repository containts Golang implementation of Alarm Adapter and related application library interface.
+
+Architecture
+------------
+
+![Architecture](assets/alarm-adapter.png)
+
+The **Alarm Library** provides a simple interface for RIC applications (both platform application and xApps) to raise, clear and re-raise. The **Alarm Library** interacts with the **Alarm Adapter** via RMR interface.
+
+The **Alarm Adapter** is reponsible for managing alarm situations in RIC cluster and interfacing with **Northboubd** applications such as **Prometheus AlertManager** to pass the alarms.
+
+Overview for Alarm Adapter
+--------------------------
+
+### TBD
+
+Overview for Alarm Library
+--------------------------
+
+## Initialization
+
+A new alarm instance is created with InitAlarm function. MO and application identities are given as a parameter.
+
+## Alarm Context and Format
+
+The Alarm object contains following parameters:
+ * *SpecificProblem*: problem that is the cause of the alarm
+ * *PerceivedSeverity*: The severity of the alarm, see above for possible values
+ * *ManagedObjectId*: The name of the managed object that is the cause of the fault
+ * *ApplicationId*: The name of the process raised the alarm
+ * *AdditionalInfo*: Additional information given by the application
+ * *IdentifyingInfo*: Identifying additional information, which is part of alarm identity
+
+## Alarm APIs
+* *Raise*: Raises the alarm instance given as a parameter
+* *Clear*: Clears the alarm instance given as a parameter, if it the alarm active
+* *Reraise*: Attempts to re-raise the alarm instance given as a parameter
+* *ClearAll*: Clears all alarms matching moId and appId given as parameters
+
+## Example
+-------
+
+```go
+package main
+
+import (
+ alarm "gerrit.o-ran-sc.org/r/ric-plt/alarm-go/alarm"
+)
+
+func main() {
+ // Initialize the alarm component
+ alarmer, err := alarm.InitAlarm("my-pod", "my-app")
+
+ // Create a new Alarm object
+ alarm := alarmer.NewAlarm(1234, alarm.SeverityMajor, "Some App data", "eth 0 1")
+
+ // Raise an alarm (SP=1234, etc)
+ err := alarmer.Raise(alarm)
+
+ // Clear an alarm (SP=1234)
+ err := alarmer.Clear(alarm)
+
+ // Re-raise an alarm (SP=1234)
+ err := alarmer.Reraise(alarm)
+
+ // Clear all alarms raised by the application
+ err := alarmer.Reraise()
+}
+```
+
+CI
+--
+
+The Dockerfile in the `ci` directory _only_ runs, when build, the library unit tests for the repository.
+
+License
+-------
+ Copyright (c) 2020 AT&T Intellectual Property.
+ Copyright (c) 2020 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.
+
+ This source code is part of the near-RT RIC (RAN Intelligent Controller)
+ platform project (RICP).
+
+
+
--- /dev/null
+/*
+ * Copyright (c) 2020 AT&T Intellectual Property.
+ * Copyright (c) 2020 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.
+ *
+ * This source code is part of the near-RT RIC (RAN Intelligent Controller)
+ * platform project (RICP).
+ */
+package main
+
+import (
+ "log"
+)
+
+func main() {
+ log.Println("Not implemented yet!")
+}
--- /dev/null
+/*
+ * Copyright (c) 2020 AT&T Intellectual Property.
+ * Copyright (c) 2020 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.
+ *
+ * This source code is part of the near-RT RIC (RAN Intelligent Controller)
+ * platform project (RICP).
+ */
+
+package alarm
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "log"
+ "sync"
+ "time"
+ "unsafe"
+)
+
+/*
+#cgo CFLAGS: -I../
+#cgo LDFLAGS: -lrmr_nng -lnng
+
+#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,
+ }
+
+ return r, nil
+ }
+
+ return nil, errors.New("rmrInit failed!")
+}
+
+// Create a new Alarm instance
+func (r *RICAlarm) NewAlarm(sp int, severity Severity, ainfo, iinfo string) Alarm {
+ return Alarm{
+ ManagedObjectId: r.moId,
+ ApplicationId: r.appId,
+ SpecificProblem: sp,
+ PerceivedSeverity: severity,
+ AdditionalInfo: ainfo,
+ IdentifyingInfo: iinfo,
+ }
+}
+
+// Create a new AlarmMessage instance
+func (r *RICAlarm) NewAlarmMessage(a Alarm, alarmAction AlarmAction) AlarmMessage {
+ alarmTime := time.Now().UnixNano() / 1000
+ return AlarmMessage{a, alarmAction, alarmTime}
+}
+
+// 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)
+}
+
+// Clear a RIC alarm
+func (r *RICAlarm) Clear(a Alarm) error {
+ r.mutex.Lock()
+ defer r.mutex.Unlock()
+
+ m := r.NewAlarmMessage(a, AlarmActionClear)
+ return r.SendMessage(m)
+}
+
+// Re-raise a RIC alarm
+func (r *RICAlarm) Reraise(a Alarm) error {
+ r.mutex.Lock()
+ defer r.mutex.Unlock()
+
+ m := r.NewAlarmMessage(a, AlarmActionReraise)
+ return r.SendMessage(m)
+}
+
+// Clear all alarms raised by the application
+func (r *RICAlarm) ClearAll() error {
+ r.mutex.Lock()
+ defer r.mutex.Unlock()
+
+ a := r.NewAlarm(0, SeverityDefault, "", "")
+ m := r.NewAlarmMessage(a, AlarmActionClearAll)
+
+ return r.SendMessage(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))
+
+ payload, err := json.Marshal(a)
+ if err != nil {
+ return err
+ }
+
+ 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 {
+ return errors.New(fmt.Sprintf("rmrSend failed with error: %d", state))
+ }
+ return nil
+}
+
+func (r *RICAlarm) ReceiveMessage(cb func(AlarmMessage)) error {
+ if rbuf := C.rmrRcv(r.rmrCtx); rbuf != nil {
+ payload := C.GoBytes(unsafe.Pointer(rbuf.payload), C.int(rbuf.len))
+ a := AlarmMessage{}
+ if err := json.Unmarshal(payload, &a); err == nil {
+ cb(a)
+ }
+ }
+ return errors.New("rmrRcv failed!")
+}
--- /dev/null
+/*
+ * Copyright (c) 2020 AT&T Intellectual Property.
+ * Copyright (c) 2020 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.
+ *
+ * This source code is part of the near-RT RIC (RAN Intelligent Controller)
+ * platform project (RICP).
+ */
+
+package alarm_test
+
+import (
+ "github.com/stretchr/testify/assert"
+ "testing"
+ "time"
+
+ "gerrit.o-ran-sc.org/r/ric-plt/alarm-go/alarm"
+)
+
+var alarmer *alarm.RICAlarm
+
+// Test cases
+func TestAlarmInitSuccess(t *testing.T) {
+ a, err := alarm.InitAlarm("my-pod", "my-app")
+ assert.Nil(t, err, "init failed")
+ assert.Equal(t, false, a == nil)
+
+ alarmer = a
+}
+
+func TestAlarmRaiseSuccess(t *testing.T) {
+ a := alarmer.NewAlarm(1234, alarm.SeverityMajor, "Some App data", "eth 0 1")
+
+ err := alarmer.Raise(a)
+ assert.Nil(t, err, "raise failed")
+}
+
+func TestAlarmClearSuccess(t *testing.T) {
+ a := alarmer.NewAlarm(1234, alarm.SeverityMajor, "Some App data", "eth 0 1")
+
+ err := alarmer.Clear(a)
+ assert.Nil(t, err, "clear failed")
+}
+
+func TestAlarmReraiseSuccess(t *testing.T) {
+ a := alarmer.NewAlarm(1234, alarm.SeverityMajor, "Some App data", "eth 0 1")
+
+ err := alarmer.Reraise(a)
+ assert.Nil(t, err, "re-raise failed")
+}
+
+func TestAlarmClearAllSuccess(t *testing.T) {
+ err := alarmer.ClearAll()
+ assert.Nil(t, err, "clearAll failed")
+}
+
+func TestAlarmSendSuccess(t *testing.T) {
+ a := alarmer.NewAlarm(1234, alarm.SeverityMajor, "Some App data", "eth 0 1")
+
+ consumer := func(m alarm.AlarmMessage) {
+ assert.Equal(t, m.ManagedObjectId, a.ManagedObjectId)
+ assert.Equal(t, m.ApplicationId, a.ApplicationId)
+ assert.Equal(t, m.SpecificProblem, a.SpecificProblem)
+ assert.Equal(t, m.PerceivedSeverity, a.PerceivedSeverity)
+ assert.Equal(t, m.AdditionalInfo, a.AdditionalInfo)
+ assert.Equal(t, m.IdentifyingInfo, a.IdentifyingInfo)
+ assert.Equal(t, m.AlarmAction, alarm.AlarmActionRaise)
+ }
+
+ go alarmer.ReceiveMessage(consumer)
+ time.Sleep(time.Duration(1 * time.Second))
+
+ m := alarmer.NewAlarmMessage(a, alarm.AlarmActionRaise)
+ err := alarmer.SendMessage(m)
+ assert.Nil(t, err, "send failed")
+}
--- /dev/null
+module gerrit.o-ran-sc.org/r/ric-plt/alarm-go/alarm
+
+go 1.13
+
+require github.com/stretchr/testify v1.5.1
--- /dev/null
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
--- /dev/null
+/*
+==================================================================================
+ Copyright (c) 2020 AT&T Intellectual Property.
+ Copyright (c) 2020 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.
+==================================================================================
+*/
+
+#include <string.h>
+#include "utils.h"
+
+void * rmrInit(void) {
+ void* mrc; // msg router context
+
+ if( (mrc = rmr_init("tcp:4588", 1024, RMRFL_NONE)) == NULL ) {
+ fprintf(stderr, "Unable to initialize RMR\n");
+ return NULL;
+ }
+
+ // Must have a route table before we can send, so wait til RMR is ready
+ while(!rmr_ready(mrc)) {
+ fprintf(stderr, "Waiting for RMR to be ready ...\n");
+ sleep(1);
+ }
+ fprintf(stderr, "RMR is ready now ...\n");
+
+ return mrc;
+}
+
+int rmrSend(void *mrc, int mtype, void *payload, int payload_len, char *meid) {
+ int retry_count = 0;
+ rmr_mbuf_t *sbuf = rmr_alloc_msg(mrc, 1024);
+
+ sbuf->mtype = mtype;
+ sbuf->sub_id = RMR_VOID_SUBID;
+ sbuf->state = 0;
+ sbuf->len = payload_len;
+ memcpy(sbuf->payload, payload, payload_len);
+ rmr_str2meid(sbuf, meid);
+
+ do {
+ sbuf = rmr_send_msg(mrc, sbuf);
+ if (sbuf == NULL) {
+ return -1;
+ }
+
+ if (sbuf->state == RMR_OK) {
+ break;
+ }
+ } while(sbuf->state == RMR_ERR_RETRY && ++retry_count < 10);
+
+ return sbuf->state;
+}
+
+rmr_mbuf_t * rmrRcv(void *mrc) {
+ while(1) {
+ rmr_mbuf_t *rbuf = rmr_rcv_msg(mrc, NULL);
+ if (rbuf != NULL && rbuf->state == RMR_OK) {
+ return rbuf;
+ }
+ }
+
+ return NULL;
+}
+
--- /dev/null
+/*
+==================================================================================
+ Copyright (c) 2020 AT&T Intellectual Property.
+ Copyright (c) 2020 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.
+==================================================================================
+*/
+
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <rmr/rmr.h>
+
+void * rmrInit(void);
+int rmrSend(void *mrc, int mtype, void *payload, int payload_len, char *meid);
+rmr_mbuf_t * rmrRcv(void *mrc);
+
+#endif
--- /dev/null
+# Copyright (c) 2020 AT&T Intellectual Property.
+# Copyright (c) 2020 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.
+#
+# This source code is part of the near-RT RIC (RAN Intelligent Controller)
+# platform project (RICP).
+
+FROM golang:1.12
+
+RUN mkdir -p /tmp/alarm
+COPY . /tmp/alarm
+RUN cd /tmp/alarm/lib && go test . -v -coverprofile cover.out