/dist/
/nbdist/
/.nb-gradle/
-/build/
### visual studio ###
.vs
-RIC Alarm Adapter and Library Interface
+RIC Alarm Manager and Library Interface
=======================================
-This repository containts Golang implementation of Alarm Adapter and related application library interface.
+This repository containts Golang implementation of Alarm Manager 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 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 Manager** via RMR interface.
-The **Alarm Adapter** is responsible for managing alarm situations in RIC cluster and interfacing with **Northboubd** applications such as **Prometheus AlertManager** to post the alarms as alerts. AlertManager takes care of deduplicating, silencing and inhibition (suppressing) of alerts, and routing them to the VESAgent, which, in turn, takes care of converting alerts to fault and send to ONAP as VES events.
+The **Alarm Manager** is responsible for managing alarm situations in RIC cluster and interfacing with **Northboubd** applications such as **Prometheus AlertManager** to post the alarms as alerts. AlertManager takes care of deduplicating, silencing and inhibition (suppressing) of alerts, and routing them to the VESAgent, which, in turn, takes care of converting alerts to fault and send to ONAP as VES events.
-Overview for Alarm Adapter
+Overview for Alarm Manager
--------------------------
### TBD
r := &RICAlarm{
moId: mo,
appId: id,
- adapterUrl: ALARM_ADAPTER_HTTP_URL,
+ managerUrl: ALARM_MANAGER_HTTP_URL,
}
- if os.Getenv("ALARM_ADAPTER_URL") != "" {
- r.adapterUrl = os.Getenv("ALARM_ADAPTER_URL")
+ if os.Getenv("ALARM_MANAGER_URL") != "" {
+ r.managerUrl = os.Getenv("ALARM_MANAGER_URL")
}
if os.Getenv("ALARM_IF_RMR") != "" {
log.Println("Sending alarm: ", fmt.Sprintf("%s", payload))
if r.rmrCtx == nil || !r.rmrReady {
- url := fmt.Sprintf("%s/%s", r.adapterUrl, "ric/v1/alarms")
+ 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)
func InitRMR(r *RICAlarm) error {
// Setup static RT for alarm system
- endpoint := ALARM_ADAPTER_RMR_URL
+ endpoint := ALARM_MANAGER_RMR_URL
if r.moId == "my-pod" {
endpoint = "localhost:4560"
} else if r.moId == "my-pod-lib" {
)
var alarmer *alarm.RICAlarm
-var adapterSim *httptest.Server
+var managerSim *httptest.Server
// Test cases
func TestAlarmInitSuccess(t *testing.T) {
- os.Setenv("ALARM_ADAPTER_URL", "http://localhost:8080")
- adapterSim = CreateAlarmAdapterSim(t, "POST", "/ric/v1/alarms", http.StatusOK, nil)
+ os.Setenv("ALARM_MANAGER_URL", "http://localhost:8080")
+ managerSim = CreateAlarmManagerSim(t, "POST", "/ric/v1/alarms", http.StatusOK, nil)
a, err := alarm.InitAlarm("my-pod-lib", "my-app")
assert.Nil(t, err, "init failed")
}
func TestTeardown(t *testing.T) {
- adapterSim.Close()
+ managerSim.Close()
}
-func CreateAlarmAdapterSim(t *testing.T, method, url string, status int, respData interface{}) *httptest.Server {
+func CreateAlarmManagerSim(t *testing.T, method, url string, status int, respData interface{}) *httptest.Server {
l, err := net.Listen("tcp", "localhost:8080")
if err != nil {
t.Error("Failed to create listener: " + err.Error())
type RICAlarm struct {
moId string
appId string
- adapterUrl string
+ managerUrl string
rmrCtx unsafe.Pointer
rmrReady bool
mutex sync.Mutex
}
const (
- ALARM_ADAPTER_HTTP_URL string = "http://service-ricplt-alarmadapter-http.ricplt:8080"
- ALARM_ADAPTER_RMR_URL string = "service-ricplt-alarmadapter-rmr.ricplt:4560"
+ ALARM_MANAGER_HTTP_URL string = "http://service-ricplt-alarmmanager-http.ricplt:8080"
+ ALARM_MANAGER_RMR_URL string = "service-ricplt-alarmmanager-rmr.ricplt:4560"
)
# platform project (RICP).
#==================================================================================
-FROM nexus3.o-ran-sc.org:10004/o-ran-sc/bldr-ubuntu18-c-go:9-u18.04 as ubuntu-alarmadapter
+FROM nexus3.o-ran-sc.org:10004/o-ran-sc/bldr-ubuntu18-c-go:9-u18.04 as ubuntu-alarm-manager
# Install utilities
RUN apt update && apt install -y iputils-ping net-tools curl sudo
# Install dependencies, compile and test the module
-RUN mkdir -p /go/src/alarm-adapter
-COPY . /go/src/alarm-adapter
+RUN mkdir -p /go/src/am
+COPY . /go/src/am
-WORKDIR "/go/src/alarm-adapter/adapter"
-RUN ./build_adapter_ubuntu.sh
+WORKDIR "/go/src/am"
+RUN ./build/build_ubuntu.sh
# Final, executable and deployable container
FROM ubuntu:18.04
-COPY --from=ubuntu-alarmadapter /go/src/alarm-adapter/adapter/run_adapter.sh /
-COPY --from=ubuntu-alarmadapter /go/src/alarm-adapter/adapter/alarm-adapter /
-COPY --from=ubuntu-alarmadapter /go/src/alarm-adapter/config/* /
-COPY --from=ubuntu-alarmadapter /usr/local/lib /usr/local/lib
+COPY --from=ubuntu-alarm-manager /go/src/am/build/run.sh /
+COPY --from=ubuntu-alarm-manager /go/src/am/manager/alarm-manager /
+COPY --from=ubuntu-alarm-manager /go/src/am/config/* /
+COPY --from=ubuntu-alarm-manager /usr/local/lib /usr/local/lib
RUN ldconfig
-RUN chmod 755 /run_adapter.sh
-CMD /run_adapter.sh
+RUN chmod 755 /run.sh
+CMD /run.sh
set -eux
-echo "--> build_adapter_ubuntu.sh starts"
+echo "--> build_ubuntu.sh starts"
# Install RMR from deb packages at packagecloud.io
rmr=rmr_4.0.2_amd64.deb
hash=$(git rev-parse --short HEAD || true)
+ROOT_DIR=$PWD
+
# Build
-go build -a -installsuffix cgo -ldflags "-X main.Version=$tag -X main.Hash=$hash" -o alarm-adapter ./cmd/*.go
+cd ${ROOT_DIR}/manager && go build -a -installsuffix cgo -ldflags "-X main.Version=$tag -X main.Hash=$hash" -o alarm-manager ./cmd/*.go
# Execute UT and measure coverage for the Alarm Library
-cd ../alarm && go test . -v -coverprofile cover.out
+cd ${ROOT_DIR}/alarm && go test . -v -coverprofile cover.out
+
+# And for the Alarm Manager
+cd ${ROOT_DIR}/manager && go test -v -p 1 -coverprofile cover.out ./cmd/ -c -o ./manager_test && ./manager_test
-# And for the Alarm Adapter
-cd ../adapter && go test -v -p 1 -coverprofile cover.out ./cmd/ -c -o ./adapter_test && ./adapter_test
+# Finally compile the CLI
+cd ${ROOT_DIR}/cli && go build -a -installsuffix cgo alarm-cli.go
-echo "--> build_adapter_ubuntu.sh ends"
+echo "--> build_ubuntu.sh ends"
#==================================================================================
#
#
-# Mnemonic: run_adapter.sh
-# Abstract: Starts the alarm adapter service
+# Mnemonic: run.sh
+# Abstract: Starts the alarm manager service
# Date: 10 March 2020
#
export RMR_SEED_RT=./uta_rtg.rt
-export RMR_SRC_ID="service-ricplt-alarmadapter-rmr.ricplt"
+export RMR_SRC_ID="service-ricplt-alarmmanager-rmr.ricplt"
-exec ./alarm-adapter -f ./config-file.json
+exec ./alarm-manager -f ./config-file.json
--- /dev/null
+#!/bin/sh -e
+#
+#==================================================================================
+# 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.
+#==================================================================================
+#
+#
+# Mnemonic: run.sh
+# Abstract: Starts the alarm manager service
+# Date: 10 March 2020
+#
+export RMR_SEED_RT=$PWD/config/uta_rtg.rt
+export RMR_SRC_ID="service-ricplt-alarmmanager-rmr.ricplt"
+
+$PWD/manager/alarm-manager -f $PWD/config/config-file.json
}
json.Unmarshal([]byte(body), &alarms)
- fmt.Println(alarms)
return alarms
}
t := table.NewWriter()
t.SetOutputMirror(os.Stdout)
if isHistory {
- t.AppendHeader(table.Row{"SP", "MOID", "APPID", "IINFO", "SEVERITY", "AAI", "TIME", "ACTION"})
+ t.AppendHeader(table.Row{"SP", "MOID", "APPID", "IINFO", "SEVERITY", "AAI", "ACTION", "TIME"})
} else {
t.AppendHeader(table.Row{"SP", "MOID", "APPID", "IINFO", "SEVERITY", "AAI", "TIME"})
}
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},
+ {a.SpecificProblem, a.ManagedObjectId, a.ApplicationId, a.IdentifyingInfo, a.PerceivedSeverity, a.AdditionalInfo, a.AlarmAction, alarmTime},
})
} else {
t.AppendRows([]table.Row{
{
"local": {
- "host": ":8080"
+ "host": ":8089"
},
"logger": {
"level": 4
# By default this file is in the docker build directory,
# but the location can configured in the JJB template.
---
-tag: 0.5.0
+tag: 0.5.1
app "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
)
-func (a *AlarmAdapter) StartAlertTimer() {
+func (a *AlarmManager) StartAlertTimer() {
tick := time.Tick(time.Duration(a.alertInterval) * time.Millisecond)
for range tick {
a.mutex.Lock()
}
}
-func (a *AlarmAdapter) Consume(rp *app.RMRParams) (err error) {
+func (a *AlarmManager) Consume(rp *app.RMRParams) (err error) {
app.Logger.Info("Message received!")
defer app.Rmr.Free(rp.Mbuf)
return nil
}
-func (a *AlarmAdapter) HandleAlarms(rp *app.RMRParams) (*alert.PostAlertsOK, error) {
+func (a *AlarmManager) HandleAlarms(rp *app.RMRParams) (*alert.PostAlertsOK, error) {
var m alarm.AlarmMessage
app.Logger.Info("Received JSON: %s", rp.Payload)
if err := json.Unmarshal(rp.Payload, &m); err != nil {
return a.ProcessAlarm(&m)
}
-func (a *AlarmAdapter) ProcessAlarm(m *alarm.AlarmMessage) (*alert.PostAlertsOK, error) {
+func (a *AlarmManager) ProcessAlarm(m *alarm.AlarmMessage) (*alert.PostAlertsOK, error) {
if _, ok := alarm.RICAlarmDefinitions[m.Alarm.SpecificProblem]; !ok {
app.Logger.Warn("Alarm (SP='%d') not recognized, suppressing ...", m.Alarm.SpecificProblem)
return nil, nil
return nil, nil
}
-func (a *AlarmAdapter) IsMatchFound(newAlarm alarm.Alarm) (int, bool) {
+func (a *AlarmManager) 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 {
return -1, false
}
-func (a *AlarmAdapter) RemoveAlarm(alarms []alarm.AlarmMessage, i int, listName string) []alarm.AlarmMessage {
+func (a *AlarmManager) RemoveAlarm(alarms []alarm.AlarmMessage, i int, listName string) []alarm.AlarmMessage {
a.mutex.Lock()
defer a.mutex.Unlock()
return alarms[:len(alarms)-1]
}
-func (a *AlarmAdapter) UpdateAlarmLists(newAlarm *alarm.AlarmMessage) {
+func (a *AlarmManager) UpdateAlarmLists(newAlarm *alarm.AlarmMessage) {
a.mutex.Lock()
defer a.mutex.Unlock()
a.alarmHistory = append(a.alarmHistory, *newAlarm)
}
-func (a *AlarmAdapter) GenerateAlertLabels(newAlarm alarm.Alarm, status AlertStatus) (models.LabelSet, models.LabelSet) {
+func (a *AlarmManager) GenerateAlertLabels(newAlarm alarm.Alarm, status AlertStatus) (models.LabelSet, models.LabelSet) {
alarmDef := alarm.RICAlarmDefinitions[newAlarm.SpecificProblem]
amLabels := models.LabelSet{
"status": string(status),
return amLabels, amAnnotations
}
-func (a *AlarmAdapter) NewAlertmanagerClient() *client.Alertmanager {
+func (a *AlarmManager) NewAlertmanagerClient() *client.Alertmanager {
cr := clientruntime.New(a.amHost, a.amBaseUrl, a.amSchemes)
return client.New(cr, strfmt.Default)
}
-func (a *AlarmAdapter) PostAlert(amLabels, amAnnotations models.LabelSet) (*alert.PostAlertsOK, error) {
+func (a *AlarmManager) PostAlert(amLabels, amAnnotations models.LabelSet) (*alert.PostAlertsOK, error) {
pa := &models.PostableAlert{
Alert: models.Alert{
GeneratorURL: strfmt.URI(""),
return ok, err
}
-func (a *AlarmAdapter) StatusCB() bool {
+func (a *AlarmManager) StatusCB() bool {
if !a.rmrReady {
app.Logger.Info("RMR not ready yet!")
}
return a.rmrReady
}
-func (a *AlarmAdapter) Run(sdlcheck bool) {
- app.Logger.SetMdc("alarmAdapter", fmt.Sprintf("%s:%s", Version, Hash))
+func (a *AlarmManager) Run(sdlcheck bool) {
+ app.Logger.SetMdc("alarmManager", fmt.Sprintf("%s:%s", Version, Hash))
app.SetReadyCB(func(d interface{}) { a.rmrReady = true }, true)
app.Resource.InjectStatusCb(a.StatusCB)
app.RunWithParams(a, sdlcheck)
}
-func NewAlarmAdapter(amHost string, alertInterval int) *AlarmAdapter {
+func NewAlarmManager(amHost string, alertInterval int) *AlarmManager {
if alertInterval == 0 {
alertInterval = viper.GetInt("controls.promAlertManager.alertInterval")
}
amHost = viper.GetString("controls.promAlertManager.address")
}
- return &AlarmAdapter{
+ return &AlarmManager{
rmrReady: false,
amHost: amHost,
amBaseUrl: viper.GetString("controls.promAlertManager.baseUrl"),
// Main function
func main() {
- NewAlarmAdapter("", 0).Run(true)
+ NewAlarmManager("", 0).Run(true)
}
"github.com/prometheus/alertmanager/api/v2/models"
)
-var alarmAdapter *AlarmAdapter
+var alarmManager *AlarmManager
var alarmer *alarm.RICAlarm
var eventChan chan string
// Test cases
func TestMain(M *testing.M) {
os.Setenv("ALARM_IF_RMR", "true")
- alarmAdapter = NewAlarmAdapter("localhost:9093", 500)
- go alarmAdapter.Run(false)
+ alarmManager = NewAlarmManager("localhost:9093", 500)
+ go alarmManager.Run(false)
time.Sleep(time.Duration(2) * time.Second)
// Wait until RMR is up-and-running
assert.Nil(t, alarmer.Clear(a), "clear failed")
time.Sleep(time.Duration(2) * time.Second)
- assert.Equal(t, len(alarmAdapter.activeAlarms), 0)
+ assert.Equal(t, len(alarmManager.activeAlarms), 0)
}
func TestMultipleAlarmsRaisedSucess(t *testing.T) {
assert.Nil(t, alarmer.Clear(b), "clear failed")
time.Sleep(time.Duration(2) * time.Second)
- assert.Equal(t, len(alarmAdapter.activeAlarms), 0)
+ assert.Equal(t, len(alarmManager.activeAlarms), 0)
}
func TestAlarmsSuppresedSucess(t *testing.T) {
}
func TestAlarmHandlingErrorCases(t *testing.T) {
- ok, err := alarmAdapter.HandleAlarms(&xapp.RMRParams{})
+ ok, err := alarmManager.HandleAlarms(&xapp.RMRParams{})
assert.Equal(t, err.Error(), "unexpected end of JSON input")
assert.Nil(t, ok, "raise failed")
}
func TestConsumeUnknownMessage(t *testing.T) {
- err := alarmAdapter.Consume(&xapp.RMRParams{})
+ err := alarmManager.Consume(&xapp.RMRParams{})
assert.Nil(t, err, "raise failed")
}
func TestStatusCallback(t *testing.T) {
- assert.Equal(t, true, alarmAdapter.StatusCB())
+ assert.Equal(t, true, alarmManager.StatusCB())
}
func VerifyAlarm(t *testing.T, a alarm.Alarm, expectedCount int) string {
receivedAlert := waitForEvent()
- assert.Equal(t, len(alarmAdapter.activeAlarms), expectedCount)
- _, ok := alarmAdapter.IsMatchFound(a)
+ assert.Equal(t, len(alarmManager.activeAlarms), expectedCount)
+ _, ok := alarmManager.IsMatchFound(a)
assert.True(t, ok)
return receivedAlert
app "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
)
-func (a *AlarmAdapter) respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
+func (a *AlarmManager) respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
if payload != nil {
}
}
-func (a *AlarmAdapter) GetActiveAlarms(w http.ResponseWriter, r *http.Request) {
+func (a *AlarmManager) GetActiveAlarms(w http.ResponseWriter, r *http.Request) {
app.Logger.Info("GetActiveAlarms: %+v", a.activeAlarms)
a.respondWithJSON(w, http.StatusOK, a.activeAlarms)
}
-func (a *AlarmAdapter) GetAlarmHistory(w http.ResponseWriter, r *http.Request) {
+func (a *AlarmManager) GetAlarmHistory(w http.ResponseWriter, r *http.Request) {
app.Logger.Info("GetAlarmHistory: %+v", a.alarmHistory)
a.respondWithJSON(w, http.StatusOK, a.alarmHistory)
}
-func (a *AlarmAdapter) RaiseAlarm(w http.ResponseWriter, r *http.Request) {
+func (a *AlarmManager) RaiseAlarm(w http.ResponseWriter, r *http.Request) {
if err := a.doAction(w, r, true); err != nil {
a.respondWithJSON(w, http.StatusOK, err)
}
}
-func (a *AlarmAdapter) ClearAlarm(w http.ResponseWriter, r *http.Request) {
+func (a *AlarmManager) ClearAlarm(w http.ResponseWriter, r *http.Request) {
if err := a.doAction(w, r, false); err != nil {
a.respondWithJSON(w, http.StatusOK, err)
}
}
-func (a *AlarmAdapter) doAction(w http.ResponseWriter, r *http.Request, isRaiseAlarm bool) error {
+func (a *AlarmManager) doAction(w http.ResponseWriter, r *http.Request, isRaiseAlarm bool) error {
app.Logger.Info("doAction: request received = %t", isRaiseAlarm)
if r.Body == nil {
return err
}
-func (a *AlarmAdapter) HandleViaRmr(d alarm.Alarm, isRaiseAlarm bool) error {
+func (a *AlarmManager) HandleViaRmr(d alarm.Alarm, isRaiseAlarm bool) error {
alarmClient, err := alarm.InitAlarm(d.ManagedObjectId, d.ApplicationId)
if err != nil {
app.Logger.Error("json.NewDecoder failed: %v", err)
}
rr := httptest.NewRecorder()
- handler := http.HandlerFunc(alarmAdapter.GetActiveAlarms)
+ handler := http.HandlerFunc(alarmManager.GetActiveAlarms)
handler.ServeHTTP(rr, req)
assert.Equal(t, true, rr != nil)
}
rr := httptest.NewRecorder()
- handler := http.HandlerFunc(alarmAdapter.RaiseAlarm)
+ handler := http.HandlerFunc(alarmManager.RaiseAlarm)
handler.ServeHTTP(rr, req)
assert.True(t, rr != nil)
}
rr := httptest.NewRecorder()
- handler := http.HandlerFunc(alarmAdapter.ClearAlarm)
+ handler := http.HandlerFunc(alarmManager.ClearAlarm)
handler.ServeHTTP(rr, req)
assert.Equal(t, true, rr != nil)
"gerrit.o-ran-sc.org/r/ric-plt/alarm-go/alarm"
)
-type AlarmAdapter struct {
+type AlarmManager struct {
amHost string
amBaseUrl string
amSchemes []string
project: ric-plt/alarm-go
ref: c8687a0e843eb98d91f3f669a2d3dcc680def039
containers:
- - name: ric-plt-alarmadapter
- version: 0.4.5
+ - name: ric-plt-alarmmanager
+ version: 0.5.1