From 3e0381545172d07ba76b9e84e41334a2e9cf66e4 Mon Sep 17 00:00:00 2001 From: Mohamed Abukar Date: Wed, 4 Mar 2020 10:01:45 +0200 Subject: [PATCH] Initial alarm library implementation Signed-off-by: Mohamed Abukar Change-Id: I1b824d422139d2135cd89905b432824afc7be71a --- README.md | 100 ++++++++++++++++++++++++ adapter/cmd/adapter.go | 28 +++++++ alarm/alarm.go | 197 +++++++++++++++++++++++++++++++++++++++++++++++ alarm/alarm_test.go | 87 +++++++++++++++++++++ alarm/go.mod | 5 ++ alarm/go.sum | 10 +++ alarm/utils.c | 76 ++++++++++++++++++ alarm/utils.h | 34 ++++++++ assets/alarm-adapter.png | Bin 0 -> 30322 bytes ci/Dockerfile | 23 ++++++ 10 files changed, 560 insertions(+) create mode 100755 README.md create mode 100755 adapter/cmd/adapter.go create mode 100755 alarm/alarm.go create mode 100755 alarm/alarm_test.go create mode 100644 alarm/go.mod create mode 100644 alarm/go.sum create mode 100755 alarm/utils.c create mode 100755 alarm/utils.h create mode 100755 assets/alarm-adapter.png create mode 100755 ci/Dockerfile diff --git a/README.md b/README.md new file mode 100755 index 0000000..5e42c3d --- /dev/null +++ b/README.md @@ -0,0 +1,100 @@ +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). + + + diff --git a/adapter/cmd/adapter.go b/adapter/cmd/adapter.go new file mode 100755 index 0000000..3a1ee02 --- /dev/null +++ b/adapter/cmd/adapter.go @@ -0,0 +1,28 @@ +/* + * 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!") +} diff --git a/alarm/alarm.go b/alarm/alarm.go new file mode 100755 index 0000000..2246abe --- /dev/null +++ b/alarm/alarm.go @@ -0,0 +1,197 @@ +/* + * 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!") +} diff --git a/alarm/alarm_test.go b/alarm/alarm_test.go new file mode 100755 index 0000000..ea56b00 --- /dev/null +++ b/alarm/alarm_test.go @@ -0,0 +1,87 @@ +/* + * 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") +} diff --git a/alarm/go.mod b/alarm/go.mod new file mode 100644 index 0000000..8e4bc7f --- /dev/null +++ b/alarm/go.mod @@ -0,0 +1,5 @@ +module gerrit.o-ran-sc.org/r/ric-plt/alarm-go/alarm + +go 1.13 + +require github.com/stretchr/testify v1.5.1 diff --git a/alarm/go.sum b/alarm/go.sum new file mode 100644 index 0000000..a80206a --- /dev/null +++ b/alarm/go.sum @@ -0,0 +1,10 @@ +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= diff --git a/alarm/utils.c b/alarm/utils.c new file mode 100755 index 0000000..0827069 --- /dev/null +++ b/alarm/utils.c @@ -0,0 +1,76 @@ +/* +================================================================================== + 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 +#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; +} + diff --git a/alarm/utils.h b/alarm/utils.h new file mode 100755 index 0000000..ce67fc2 --- /dev/null +++ b/alarm/utils.h @@ -0,0 +1,34 @@ +/* +================================================================================== + 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 +#include +#include +#include +#include +#include + +void * rmrInit(void); +int rmrSend(void *mrc, int mtype, void *payload, int payload_len, char *meid); +rmr_mbuf_t * rmrRcv(void *mrc); + +#endif diff --git a/assets/alarm-adapter.png b/assets/alarm-adapter.png new file mode 100755 index 0000000000000000000000000000000000000000..1239bd3135b7cf88c92a7bfee4e266a80c0b3dca GIT binary patch literal 30322 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 literal 0 HcmV?d00001 diff --git a/ci/Dockerfile b/ci/Dockerfile new file mode 100755 index 0000000..8b33fea --- /dev/null +++ b/ci/Dockerfile @@ -0,0 +1,23 @@ +# 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 -- 2.16.6