RUN wget --content-disposition https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr_${RMRVERSION}_amd64.deb/download.deb && dpkg -i rmr_${RMRVERSION}_amd64.deb && rm -rf rmr_${RMRVERSION}_amd64.deb
RUN wget --content-disposition https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr-dev_${RMRVERSION}_amd64.deb/download.deb && dpkg -i rmr-dev_${RMRVERSION}_amd64.deb && rm -rf rmr-dev_${RMRVERSION}_amd64.deb
-ENV GOLANG_VERSION 1.12.1
-RUN wget --quiet https://dl.google.com/go/go$GOLANG_VERSION.linux-amd64.tar.gz \
- && tar xvzf go$GOLANG_VERSION.linux-amd64.tar.gz -C /usr/local
ENV PATH="/usr/local/go/bin:${PATH}"
ENV GOPATH /go
GO111MODULE=on GO_ENABLED=0 GOOS=linux
# Build
-go build -a -installsuffix cgo -ldflags "-X main.Version=$tag -X main.Hash=$hash" -o alarm-adapter ./cmd/adapter.go
+go build -a -installsuffix cgo -ldflags "-X main.Version=$tag -X main.Hash=$hash" -o alarm-adapter ./cmd/*.go
# Run UT
-go test -v -p 1 -coverprofile cover.out ./cmd/ -c -o ./adapter_test && ./adapter_test
-cd ../alarm && RMR_SEED_RT=../config/uta_rtg_lib.rt go test . -v -coverprofile cover.out
+cd ../alarm && RMR_SEED_RT=../config/uta_rtg_lib.r go-acc ./
+#go test -v -p 1 -coverprofile cover.out ./cmd/ -c -o ./adapter_test && ./adapter_test
+#cd ../alarm && RMR_SEED_RT=../config/uta_rtg_lib.rt go test . -v -coverprofile cover.out
"encoding/json"
"fmt"
"time"
+ "sync"
clientruntime "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
amSchemes []string
alertInterval int
activeAlarms []alarm.Alarm
+ mutex sync.Mutex
rmrReady bool
}
-// Temp alarm constants & definitions
-const (
- RIC_RT_DISTRIBUTION_FAILED int = 8004
- CONNECTIVITY_LOST_TO_DBAAS int = 8005
- E2_CONNECTIVITY_LOST_TO_GNODEB int = 8006
- E2_CONNECTIVITY_LOST_TO_ENODEB int = 8007
-)
-
-var alarmDefinitions = map[int]string{
- RIC_RT_DISTRIBUTION_FAILED: "RIC ROUTING TABLE DISTRIBUTION FAILED",
- CONNECTIVITY_LOST_TO_DBAAS: "CONNECTIVITY LOST TO DBAAS",
- E2_CONNECTIVITY_LOST_TO_GNODEB: "E2 CONNECTIVITY LOST TO G-NODEB",
- E2_CONNECTIVITY_LOST_TO_ENODEB: "E2 CONNECTIVITY LOST TO E-NODEB",
-}
-
var Version string
var Hash string
app.SetReadyCB(func(d interface{}) { a.rmrReady = true }, true)
app.Resource.InjectStatusCb(a.StatusCB)
- app.Resource.InjectRoute("/ric/v1/alarm", a.GetActiveAlarms, "GET")
- app.Resource.InjectRoute("/ric/v1/alarm", a.GenerateAlarm, "POST")
+ app.Resource.InjectRoute("/ric/v1/alarms", a.GetActiveAlarms, "GET")
+ app.Resource.InjectRoute("/ric/v1/alarms", a.RaiseAlarm, "POST")
+ app.Resource.InjectRoute("/ric/v1/alarms", a.ClearAlarm, "DELETE")
// Start background timer for re-raising alerts
go a.StartAlertTimer()
func (a *AlarmAdapter) StartAlertTimer() {
tick := time.Tick(time.Duration(a.alertInterval) * time.Millisecond)
for range tick {
+ a.mutex.Lock()
for _, m := range a.activeAlarms {
app.Logger.Info("Re-raising alarm: %v", m)
a.PostAlert(a.GenerateAlertLabels(m))
}
+ a.mutex.Unlock()
}
}
}
app.Logger.Info("newAlarm: %v", m)
- if _, ok := alarmDefinitions[m.Alarm.SpecificProblem]; !ok {
+ if _, ok := alarm.RICAlarmDefinitions[m.Alarm.SpecificProblem]; !ok {
app.Logger.Warn("Alarm (SP='%d') not recognized, ignoring ...", m.Alarm.SpecificProblem)
return nil, nil
}
}
func (a *AlarmAdapter) RemoveAlarm(alarms []alarm.Alarm, i int) []alarm.Alarm {
+ a.mutex.Lock()
+ defer a.mutex.Unlock()
+
copy(alarms[i:], alarms[i+1:])
return alarms[:len(alarms)-1]
}
func (a *AlarmAdapter) UpdateActiveAlarms(newAlarm alarm.Alarm) {
+ a.mutex.Lock()
+ defer a.mutex.Unlock()
+
// For now just keep the active alarms in-memory. Use SDL later
a.activeAlarms = append(a.activeAlarms, newAlarm)
}
func (a *AlarmAdapter) GenerateAlertLabels(newAlarm alarm.Alarm) (models.LabelSet, models.LabelSet) {
+ alarmDef := alarm.RICAlarmDefinitions[newAlarm.SpecificProblem]
amLabels := models.LabelSet{
- "alertname": alarmDefinitions[newAlarm.SpecificProblem],
+ "alertname": alarmDef.AlarmText,
"severity": string(newAlarm.PerceivedSeverity),
"service": fmt.Sprintf("%s:%s", newAlarm.ManagedObjectId, newAlarm.ApplicationId),
"system_name": "RIC",
amAnnotations := models.LabelSet{
"description": newAlarm.IdentifyingInfo,
"additional_info": newAlarm.AdditionalInfo,
+ "summary": alarmDef.EventType,
+ "instructions": alarmDef.OperationInstructions,
}
return amLabels, amAnnotations
alertParams := alert.NewPostAlertsParams().WithAlerts(models.PostableAlerts{pa})
app.Logger.Info("Posting alerts: labels: %v, annotations: %v", amLabels, amAnnotations)
- return a.NewAlertmanagerClient().Alert.PostAlerts(alertParams)
+ ok, err := a.NewAlertmanagerClient().Alert.PostAlerts(alertParams)
+ if err != nil {
+ app.Logger.Error("Posting alerts to '%s/%s' failed with error: %v", a.amHost, a.amBaseUrl, err)
+ }
+ return ok, err
}
func (a *AlarmAdapter) StatusCB() bool {
ts := CreatePromAlertSimulator(t, "POST", "/api/v2/alerts", http.StatusOK, models.LabelSet{})
defer ts.Close()
- a := alarmer.NewAlarm(RIC_RT_DISTRIBUTION_FAILED, alarm.SeverityMajor, "Some App data", "eth 0 1")
+ a := alarmer.NewAlarm(alarm.RIC_RT_DISTRIBUTION_FAILED, alarm.SeverityMajor, "Some App data", "eth 0 1")
assert.Nil(t, alarmer.Raise(a), "raise failed")
VerifyAlarm(t, a, 1, 0)
defer ts.Close()
// Raise the alarm
- a := alarmer.NewAlarm(RIC_RT_DISTRIBUTION_FAILED, alarm.SeverityMajor, "Some App data", "eth 0 1")
+ a := alarmer.NewAlarm(alarm.RIC_RT_DISTRIBUTION_FAILED, alarm.SeverityMajor, "Some App data", "eth 0 1")
assert.Nil(t, alarmer.Raise(a), "raise failed")
VerifyAlarm(t, a, 1, 0)
// Now Clear the alarm and check alarm is removed
- a = alarmer.NewAlarm(RIC_RT_DISTRIBUTION_FAILED, alarm.SeverityCleared, "Some App data", "eth 0 1")
+ a = alarmer.NewAlarm(alarm.RIC_RT_DISTRIBUTION_FAILED, alarm.SeverityCleared, "Some App data", "eth 0 1")
assert.Nil(t, alarmer.Clear(a), "clear failed")
time.Sleep(time.Duration(2) * time.Second)
defer ts.Close()
// Raise two alarms
- a := alarmer.NewAlarm(RIC_RT_DISTRIBUTION_FAILED, alarm.SeverityMajor, "Some App data", "eth 0 1")
+ a := alarmer.NewAlarm(alarm.RIC_RT_DISTRIBUTION_FAILED, alarm.SeverityMajor, "Some App data", "eth 0 1")
assert.Nil(t, alarmer.Raise(a), "raise failed")
- b := alarmer.NewAlarm(CONNECTIVITY_LOST_TO_DBAAS, alarm.SeverityMinor, "Hello", "abcd 11")
+ b := alarmer.NewAlarm(alarm.TCP_CONNECTIVITY_LOST_TO_DBAAS, alarm.SeverityMinor, "Hello", "abcd 11")
assert.Nil(t, alarmer.Raise(b), "raise failed")
VerifyAlarm(t, a, 2, 0)
defer ts.Close()
// Raise two alarms
- a := alarmer.NewAlarm(RIC_RT_DISTRIBUTION_FAILED, alarm.SeverityMajor, "Some App data", "eth 0 1")
+ a := alarmer.NewAlarm(alarm.RIC_RT_DISTRIBUTION_FAILED, alarm.SeverityMajor, "Some App data", "eth 0 1")
assert.Nil(t, alarmer.Clear(a), "clear failed")
- b := alarmer.NewAlarm(CONNECTIVITY_LOST_TO_DBAAS, alarm.SeverityMinor, "Hello", "abcd 11")
+ b := alarmer.NewAlarm(alarm.TCP_CONNECTIVITY_LOST_TO_DBAAS, alarm.SeverityMinor, "Hello", "abcd 11")
assert.Nil(t, alarmer.Clear(b), "clear failed")
time.Sleep(time.Duration(2) * time.Second)
defer ts.Close()
// Raise two similar/matching alarms ... the second one suppresed
- a := alarmer.NewAlarm(RIC_RT_DISTRIBUTION_FAILED, alarm.SeverityMajor, "Some App data", "eth 0 1")
+ a := alarmer.NewAlarm(alarm.RIC_RT_DISTRIBUTION_FAILED, alarm.SeverityMajor, "Some App data", "eth 0 1")
assert.Nil(t, alarmer.Raise(a), "raise failed")
assert.Nil(t, alarmer.Raise(a), "raise failed")
"net/http"
"gerrit.o-ran-sc.org/r/ric-plt/alarm-go/alarm"
+ app "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
)
+var alarmClient *alarm.RICAlarm
+
func (a *AlarmAdapter) GetActiveAlarms(w http.ResponseWriter, r *http.Request) {
+ app.Logger.Info("GetActiveAlarms: request received!")
+
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
response, _ := json.Marshal(a.activeAlarms)
w.Write(response)
}
-func (a *AlarmAdapter) GenerateAlarm(w http.ResponseWriter, r *http.Request) {
+func (a *AlarmAdapter) RaiseAlarm(w http.ResponseWriter, r *http.Request) {
+ a.doAction(w, r, true)
+}
+
+func (a *AlarmAdapter) ClearAlarm(w http.ResponseWriter, r *http.Request) {
+ a.doAction(w, r, false)
+}
+
+func (a *AlarmAdapter) doAction(w http.ResponseWriter, r *http.Request, raiseAlarm bool) {
+ app.Logger.Info("doAction: request received!")
+
if r.Body == nil {
return
}
defer r.Body.Close()
- var alarmData alarm.Alarm
- if err := json.NewDecoder(r.Body).Decode(&alarmData); err == nil {
- a.UpdateActiveAlarms(alarmData)
- a.PostAlert(a.GenerateAlertLabels(alarmData))
+ var d alarm.Alarm
+ err := json.NewDecoder(r.Body).Decode(&d)
+ if err != nil {
+ app.Logger.Error("json.NewDecoder failed: %v", err)
+ return
+ }
+
+ if alarmClient == nil {
+ alarmClient, err = alarm.InitAlarm("RIC", "UEEC")
+ if err != nil {
+ app.Logger.Error("json.NewDecoder failed: %v", err)
+ return
+ }
+ }
+
+ alarmData := alarmClient.NewAlarm(d.SpecificProblem, d.PerceivedSeverity, d.AdditionalInfo, d.IdentifyingInfo)
+ if raiseAlarm {
+ alarmClient.Raise(alarmData)
+ } else {
+ alarmClient.Clear(alarmData)
}
}
--- /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 (
+ "bytes"
+ "encoding/json"
+ "github.com/stretchr/testify/assert"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "gerrit.o-ran-sc.org/r/ric-plt/alarm-go/alarm"
+)
+
+// Test cases
+func TestGetActiveAlarmsRESTInterface(t *testing.T) {
+ req, err := http.NewRequest("GET", "/ric/v1/alarms", nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rr := httptest.NewRecorder()
+ handler := http.HandlerFunc(alarmAdapter.GetActiveAlarms)
+ handler.ServeHTTP(rr, req)
+
+ assert.Equal(t, true, rr != nil)
+ assert.Equal(t, rr.Code, http.StatusOK)
+}
+
+func TestRaiseAlarmRESTInterface(t *testing.T) {
+ a := alarmer.NewAlarm(alarm.RIC_RT_DISTRIBUTION_FAILED, alarm.SeverityMajor, "Some App data", "eth 0 1")
+ b, err := json.Marshal(&a)
+ if err != nil {
+ t.Errorf("Unexpected error %v", err)
+ }
+
+ req, err := http.NewRequest("POST", "/ric/v1/alarms", bytes.NewBuffer(b))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rr := httptest.NewRecorder()
+ handler := http.HandlerFunc(alarmAdapter.RaiseAlarm)
+ handler.ServeHTTP(rr, req)
+
+ assert.True(t, rr != nil)
+ assert.Equal(t, rr.Code, http.StatusOK)
+}
+
+func TestClearAlarmRESTInterface(t *testing.T) {
+ a := alarmer.NewAlarm(alarm.RIC_RT_DISTRIBUTION_FAILED, alarm.SeverityMajor, "Some App data", "eth 0 1")
+ b, err := json.Marshal(&a)
+ if err != nil {
+ t.Errorf("Unexpected error %v", err)
+ }
+
+ req, err := http.NewRequest("POST", "/ric/v1/alarms", bytes.NewBuffer(b))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rr := httptest.NewRecorder()
+ handler := http.HandlerFunc(alarmAdapter.ClearAlarm)
+ handler.ServeHTTP(rr, req)
+
+ assert.Equal(t, true, rr != nil)
+ assert.Equal(t, rr.Code, http.StatusOK)
+}
# By default this file is in the docker build directory,
# but the location can configured in the JJB template.
---
-tag: 0.4.0
+tag: 0.4.1
"errors"
"fmt"
"log"
- "sync"
"time"
"unsafe"
)
*/
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"
- SeverityCleared 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"
- 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
-}
-
-const (
- RIC_ALARM_UPDATE = 13111
- RIC_ALARM_QUERY = 13112
-)
-
// 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.
--- /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 (
+ "sync"
+ "unsafe"
+)
+
+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"
+ SeverityCleared 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"
+ 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
+}
+
+const (
+ RIC_ALARM_UPDATE = 13111
+ RIC_ALARM_QUERY = 13112
+)
+
+// Temp alarm constants & definitions
+const (
+ RIC_RT_DISTRIBUTION_FAILED int = 8004
+ TCP_CONNECTIVITY_LOST_TO_DBAAS int = 8005
+ E2_CONNECTIVITY_LOST_TO_GNODEB int = 8006
+ E2_CONNECTIVITY_LOST_TO_ENODEB int = 8007
+)
+
+type AlarmDefinition struct {
+ AlarmId int
+ AlarmText string
+ EventType string
+ OperationInstructions string
+}
+
+var RICAlarmDefinitions = map[int]AlarmDefinition{
+ RIC_RT_DISTRIBUTION_FAILED: AlarmDefinition{
+ AlarmId: RIC_RT_DISTRIBUTION_FAILED,
+ AlarmText: "RIC ROUTING TABLE DISTRIBUTION FAILED",
+ EventType: "Processing error",
+ OperationInstructions: "Not defined",
+ },
+ TCP_CONNECTIVITY_LOST_TO_DBAAS: AlarmDefinition{
+ AlarmId: TCP_CONNECTIVITY_LOST_TO_DBAAS,
+ AlarmText: "TCP CONNECTIVITY LOST TO DBAAS",
+ EventType: "Communication error",
+ OperationInstructions: "Not defined",
+ },
+ E2_CONNECTIVITY_LOST_TO_GNODEB: AlarmDefinition{
+ AlarmId: E2_CONNECTIVITY_LOST_TO_GNODEB,
+ AlarmText: "E2 CONNECTIVITY LOST TO G-NODEB",
+ EventType: "Communication error",
+ OperationInstructions: "Not defined",
+ },
+ E2_CONNECTIVITY_LOST_TO_ENODEB: AlarmDefinition{
+ AlarmId: E2_CONNECTIVITY_LOST_TO_ENODEB,
+ AlarmText: "E2 CONNECTIVITY LOST TO E-NODEB",
+ EventType: "Communication error",
+ OperationInstructions: "Not defined",
+ },
+}
"numWorkers": 1
},
"promAlertManager": {
- "address": "service-ricplt-alertmanager-http:9093",
+ "address": "elfkp-prometheus-alertmanager:9093",
"baseUrl": "/api/v2",
"schemes": "http",
"alertInterval": 30000
gerrit.o-ran-sc.org/r/ric-plt/xapp-frame v0.0.0-00010101000000-000000000000
github.com/go-openapi/runtime v0.19.11
github.com/go-openapi/strfmt v0.19.4
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+ github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/prometheus/alertmanager v0.20.0
github.com/spf13/viper v1.6.2
github.com/stretchr/testify v1.5.1