Compare commits

..

No commits in common. "ns-o-ran" and "master" have entirely different histories.

9 changed files with 50 additions and 392 deletions

View File

@ -1,4 +1,4 @@
FROM nexus3.o-ran-sc.org:10002/o-ran-sc/bldr-ubuntu18-c-go:1.9.0 as kpimonbuild
FROM nexus3.o-ran-sc.org:10004/o-ran-sc/bldr-ubuntu18-c-go:1.9.0 as kpimonbuild
ENV PATH $PATH:/usr/local/bin
ENV GOPATH /go
@ -14,11 +14,9 @@ RUN wget --content-disposition ${RMRLIBURL} && dpkg -i rmr_${RMRVERSION}_amd64.d
RUN wget --content-disposition ${RMRDEVURL} && dpkg -i rmr-dev_${RMRVERSION}_amd64.deb
RUN rm -f rmr_${RMRVERSION}_amd64.deb rmr-dev_${RMRVERSION}_amd64.deb
RUN apt update && apt install ca-certificates libgnutls30 -y
ARG XAPPFRAMEVERSION=v0.4.11
WORKDIR /go/src/gerrit.o-ran-sc.org/r/ric-plt
RUN git clone -b cherry "https://gerrit.o-ran-sc.org/r/ric-plt/sdlgo"
RUN git clone "https://gerrit.o-ran-sc.org/r/ric-plt/sdlgo"
RUN git clone -b ${XAPPFRAMEVERSION} "https://gerrit.o-ran-sc.org/r/ric-plt/xapp-frame"
RUN cd xapp-frame && \
GO111MODULE=on go mod vendor -v && \
@ -57,14 +55,6 @@ RUN go build ./cmd/kpimon.go && pwd && ls -lat
FROM ubuntu:18.04
ENV PATH $PATH:/usr/local/bin
ENV GOPATH /go
ENV GOBIN /go/bin
ENV RMR_SEED_RT /opt/routes.txt
COPY routes.txt /opt/routes.txt
COPY --from=kpimonbuild /usr/local/lib /usr/local/lib
COPY --from=kpimonbuild /usr/local/include/e2ap/*.h /usr/local/include/e2ap/
COPY --from=kpimonbuild /usr/local/include/e2sm/*.h /usr/local/include/e2sm/
@ -74,5 +64,3 @@ COPY --from=kpimonbuild /go/src/gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/config/
WORKDIR /go/src/gerrit.o-ran-sc.org/r/scp/ric-app/kpimon
COPY --from=kpimonbuild /go/src/gerrit.o-ran-sc.org/r/scp/ric-app/kpimon/kpimon .
CMD sleep infinity

View File

@ -1,83 +1,26 @@
# UPDATED README
## PREREQUISITES
The near-RT-RIC has to be installed. If is not, follow the instructions here: https://docs.o-ran-sc.org/projects/o-ran-sc-ric-plt-ric-dep/en/latest/installation-guides.html
Take care in installing dms_cli, mandatory for the second part.
Chartmuseum has to be already on. If not availabe, run from the home folder:
>docker run --rm -u 0 -it -d -p 8090:8080 -e DEBUG=1 -e STORAGE=local -e STORAGE_LOCAL_ROOTDIR=/charts -v $(pwd)/charts:/charts chartmuseum/chartmuseum:latest
>
In addition to that, a local Docker registry is supposed to be running at 127.0.0.1:5000. In case it is not, run:
>docker run -d -p 5000:5000 --name registry registry:2
>
## Install and launch the xApp
Just use the ./launch_app.sh script.
What the script does is:
- creating an env. variable for the url of Chartmuseum.
- building the xApp from source and tagging it to 127.0.0.1.5000/{name-xapp}:version
- pushing the image to the registry (that's why it was tagged like that)
- Onboarding the xApp, using the tool *dms_cli* and the descriptor and validation schema. Notice that, inside, you find the image of the registry with its version. The xApp might have a different version. xApp version is a different thing than Docker image version.
- Installing the xApp in the RIC (notice that install = run)
- after 10 s, the script returns the name of the pod in the *ricxapp* namespace and the command to shell inside it
To run the kpimon: .
>/kpimon -f /opt/ric/config/config-file.json
# ORIGINAL README AND LICENSE
==================================================================================
Copyright (c) 2020 AT&T Intellectual Property.
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.
==================================================================================
Copyright (c) 2020 AT&T Intellectual Property.
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.
==================================================================================
KPI Monitoring
================
This repository contains the source for the RIC KPI monitoring application.
This xApp can be onboarded through the xApp Onboarder. The xapp descriptor
This xApp can be onboarded through the xApp Onboarder. The xapp descriptor
is under the xapp-descriptor/ directory.
Then the xapp can be deployed through the App Manager.
rte|12010|service-ricplt-e2term-rmr-alpha.ricplt:38000

View File

@ -1,147 +1,11 @@
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
"time"
"gerrit.o-ran-sc.org/r/scp/ric-app/kpimon/control"
)
func main() {
response_deregister, err := deRegisterXApp()
if err != nil {
print("Error: " + err.Error())
}
responseDeRegisterString := string(response_deregister)
print("RESPONSE DEREGISTER POST: ")
println(responseDeRegisterString)
time.Sleep(5 * time.Second)
response, err := registerXApp()
if err != nil {
print("Error: " + err.Error())
}
responseString := string(response)
print("RESPONSE REGISTER POST: ")
println(responseString)
time.Sleep(5 * time.Second)
c := control.NewControl()
c.Run()
}
func registerXApp() ([]byte, error) {
url := "http://service-ricplt-appmgr-http.ricplt:8080/ric/v1/register"
// Read payload from config-file.json
payload, err := ioutil.ReadFile("/opt/ric/config/config-file.json")
if err != nil {
print("Error READ CONF: " + err.Error())
}
hostname := os.Getenv("HOSTNAME")
XAPP_NAME := hostname
XAPP_VERSION := "1.0.0"
// RICPLT_NAMESPACE := "ricplt"
XAPP_NAMESPACE := "ricxapp"
// http_endpoint := "SERVICE_" + strings.ToUpper(XAPP_NAMESPACE) + "_" + strings.ToUpper(XAPP_NAME) + "_HTTP_PORT"
rmr_os_key := "SERVICE_" + strings.ToUpper(XAPP_NAMESPACE) + "_" + strings.ToUpper(XAPP_NAME) + "_RMR_PORT"
rmr_endpoint := strings.Split(os.Getenv(rmr_os_key), "//")[1]
config := string(payload)
// Create new JSON
request := map[string]interface{}{
"appName": hostname,
"appVersion": XAPP_VERSION,
"configPath": "",
"appInstanceName": XAPP_NAME,
"httpEndpoint": "",
"rmrEndpoint": rmr_endpoint,
"config": config,
}
// Encode the JSON object as a string
requestString, err := json.Marshal(request)
if err != nil {
fmt.Println("Error encoding JSON:", err)
return nil, err
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestString))
if err != nil {
return nil, err
}
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}
func deRegisterXApp() ([]byte, error) {
url := "http://service-ricplt-appmgr-http.ricplt:8080/ric/v1/deregister"
hostname := os.Getenv("HOSTNAME")
XAPP_NAME := hostname
// Create new JSON
request := map[string]interface{}{
"appName": hostname,
"appInstanceName": XAPP_NAME,
}
// Encode the JSON object as a string
requestString, err := json.Marshal(request)
if err != nil {
fmt.Println("Error encoding JSON:", err)
return nil, err
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestString))
if err != nil {
return nil, err
}
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}

View File

@ -9,22 +9,21 @@ import (
"strings"
"sync"
"time"
"gerrit.o-ran-sc.org/r/ric-plt/sdlgo"
"gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
//"github.com/go-redis/redis"
)
type Control struct {
ranList []string //nodeB list
eventCreateExpired int32 //maximum time for the RIC Subscription Request event creation procedure in the E2 Node
eventDeleteExpired int32 //maximum time for the RIC Subscription Request event deletion procedure in the E2 Node
rcChan chan *xapp.RMRParams //channel for receiving rmr message
ranList []string //nodeB list
eventCreateExpired int32 //maximum time for the RIC Subscription Request event creation procedure in the E2 Node
eventDeleteExpired int32 //maximum time for the RIC Subscription Request event deletion procedure in the E2 Node
rcChan chan *xapp.RMRParams //channel for receiving rmr message
//client *redis.Client //redis client
eventCreateExpiredMap map[string]bool //map for recording the RIC Subscription Request event creation procedure is expired or not
eventDeleteExpiredMap map[string]bool //map for recording the RIC Subscription Request event deletion procedure is expired or not
eventCreateExpiredMu *sync.Mutex //mutex for eventCreateExpiredMap
eventDeleteExpiredMu *sync.Mutex //mutex for eventDeleteExpiredMap
eventCreateExpiredMap map[string]bool //map for recording the RIC Subscription Request event creation procedure is expired or not
eventDeleteExpiredMap map[string]bool //map for recording the RIC Subscription Request event deletion procedure is expired or not
eventCreateExpiredMu *sync.Mutex //mutex for eventCreateExpiredMap
eventDeleteExpiredMu *sync.Mutex //mutex for eventDeleteExpiredMap
sdl *sdlgo.SdlInstance
}
@ -41,11 +40,7 @@ func init() {
}
func NewControl() Control {
println("Starting new control.")
// str := os.Getenv("ranList")
str := "gnb_131_133_31000000,gnb_131_133_32000000,gnb_131_133_33000000,gnb_131_133_34000000,gnb_131_133_35000000"
println("Ran list is " + str + " ---- ")
str := os.Getenv("ranList")
return Control{strings.Split(str, ","),
5, 5,
make(chan *xapp.RMRParams),
@ -95,7 +90,7 @@ func (c *Control) startTimerSubReq() {
count++
xapp.Logger.Debug("send RIC_SUB_REQ to gNodeB with cnt=%d", count)
log.Printf("send RIC_SUB_REQ to gNodeB with cnt=%d", count)
err := c.sendRicSubRequest(1001, 0, 200)
err := c.sendRicSubRequest(1001, 1001, 0)
if err != nil && count < MAX_SUBSCRIPTION_ATTEMPTS {
t.Reset(5 * time.Second)
} else {
@ -658,8 +653,8 @@ func (c *Control) handleIndication(params *xapp.RMRParams) (err error) {
xapp.Logger.Error("Failed to get ueMetrics from Redis!")
log.Printf("Failed to get ueMetrics from Redis!")
} else {
if retStr["{TS-UE-metrics},"+strconv.FormatInt(ueID, 10)] != nil {
ueJsonStr := retStr["{TS-UE-metrics},"+strconv.FormatInt(ueID, 10)].(string)
if retStr["{TS-UE-metrics}," + strconv.FormatInt(ueID, 10)] != nil {
ueJsonStr := retStr["{TS-UE-metrics}," + strconv.FormatInt(ueID, 10)].(string)
json.Unmarshal([]byte(ueJsonStr), &ueMetrics)
}
}
@ -671,7 +666,7 @@ func (c *Control) handleIndication(params *xapp.RMRParams) (err error) {
ueMetrics.UeID = ueID
log.Printf("UeID: %d", ueMetrics.UeID)
ueMetrics.ServingCellID = servingCellID
ueMetrics.ServingCellID = servingCellID
log.Printf("ServingCellID: %s", ueMetrics.ServingCellID)
ueMetrics.MeasPeriodRF = 20
@ -699,7 +694,7 @@ func (c *Control) handleIndication(params *xapp.RMRParams) (err error) {
continue
}
err = c.sdl.Set("{TS-UE-metrics},"+strconv.FormatInt(ueID, 10), newUeJsonStr)
err = c.sdl.Set("{TS-UE-metrics}," + strconv.FormatInt(ueID, 10), newUeJsonStr)
if err != nil {
xapp.Logger.Error("Failed to set UeMetrics into redis with UE ID [%d]: %v", ueID, err)
log.Printf("Failed to set UeMetrics into redis with UE ID [%d]: %v", ueID, err)
@ -752,8 +747,8 @@ func (c *Control) handleIndication(params *xapp.RMRParams) (err error) {
xapp.Logger.Error("Failed to get ueMetrics from Redis!")
log.Printf("Failed to get ueMetrics from Redis!")
} else {
if retStr["{TS-UE-metrics},"+strconv.FormatInt(ueID, 10)] != nil {
ueJsonStr := retStr["{TS-UE-metrics},"+strconv.FormatInt(ueID, 10)].(string)
if retStr["{TS-UE-metrics}," + strconv.FormatInt(ueID, 10)] != nil {
ueJsonStr := retStr["{TS-UE-metrics}," + strconv.FormatInt(ueID, 10)].(string)
json.Unmarshal([]byte(ueJsonStr), &ueMetrics)
}
}
@ -803,7 +798,7 @@ func (c *Control) handleIndication(params *xapp.RMRParams) (err error) {
continue
}
err = c.sdl.Set("{TS-UE-metrics},"+strconv.FormatInt(ueID, 10), newUeJsonStr)
err = c.sdl.Set("{TS-UE-metrics}," + strconv.FormatInt(ueID, 10), newUeJsonStr)
if err != nil {
xapp.Logger.Error("Failed to set UeMetrics into redis with UE ID [%d]: %v", ueID, err)
log.Printf("Failed to set UeMetrics into redis with UE ID [%d]: %v", ueID, err)
@ -856,8 +851,8 @@ func (c *Control) handleIndication(params *xapp.RMRParams) (err error) {
xapp.Logger.Error("Failed to get ueMetrics from Redis!")
log.Printf("Failed to get ueMetrics from Redis!")
} else {
if retStr["{TS-UE-metrics},"+strconv.FormatInt(ueID, 10)] != nil {
ueJsonStr := retStr["{TS-UE-metrics},"+strconv.FormatInt(ueID, 10)].(string)
if retStr["{TS-UE-metrics}," + strconv.FormatInt(ueID, 10)] != nil {
ueJsonStr := retStr["{TS-UE-metrics}," + strconv.FormatInt(ueID, 10)].(string)
json.Unmarshal([]byte(ueJsonStr), &ueMetrics)
}
}
@ -904,7 +899,7 @@ func (c *Control) handleIndication(params *xapp.RMRParams) (err error) {
continue
}
err = c.sdl.Set("{TS-UE-metrics},"+strconv.FormatInt(ueID, 10), newUeJsonStr)
err = c.sdl.Set("{TS-UE-metrics}," + strconv.FormatInt(ueID, 10), newUeJsonStr)
if err != nil {
xapp.Logger.Error("Failed to set UeMetrics into redis with UE ID [%d]: %v", ueID, err)
log.Printf("Failed to set UeMetrics into redis with UE ID [%d]: %v", ueID, err)
@ -935,8 +930,8 @@ func (c *Control) handleIndication(params *xapp.RMRParams) (err error) {
xapp.Logger.Error("Failed to get cellMetrics from Redis!")
log.Printf("Failed to get cellMetrics from Redis!")
} else {
if retStr["{TS-cell-metrics},"+cellIDHdr] != nil {
cellJsonStr := retStr["{TS-cell-metrics},"+cellIDHdr].(string)
if retStr["{TS-cell-metrics}," + cellIDHdr] != nil {
cellJsonStr := retStr["{TS-cell-metrics}," + cellIDHdr].(string)
json.Unmarshal([]byte(cellJsonStr), &cellMetrics)
}
}
@ -978,13 +973,14 @@ func (c *Control) handleIndication(params *xapp.RMRParams) (err error) {
continue
}
err = c.sdl.Set("{TS-cell-metrics},"+cellIDHdr, newCellJsonStr)
err = c.sdl.Set("{TS-cell-metrics}," + cellIDHdr, newCellJsonStr)
if err != nil {
xapp.Logger.Error("Failed to set CellMetrics into redis with CellID [%s]: %v", cellIDHdr, err)
log.Printf("Failed to set CellMetrics into redis with CellID [%s]: %v", cellIDHdr, err)
continue
}
//err = c.client.Set("{TS-cell-metrics}," + cellIDHdr, newCellJsonStr, 0).Err()
//if err != nil {
// xapp.Logger.Error("Failed to set CellMetrics into redis with CellID [%s]: %v", cellIDHdr, err)
@ -1125,8 +1121,8 @@ func (c *Control) setEventCreateExpiredTimer(ranName string) {
delete(c.eventCreateExpiredMap, ranName)
c.eventCreateExpiredMu.Unlock()
if !isResponsed {
xapp.Logger.Debug("RIC_SUB_REQ[%s]: RIC Event Create Timer expired!", ranName)
log.Printf("RIC_SUB_REQ[%s]: RIC Event Create Timer expired!", ranName)
xapp.Logger.Debug("RIC_SUB_REQ[%s]: RIC Event Create Timer experied!", ranName)
log.Printf("RIC_SUB_REQ[%s]: RIC Event Create Timer experied!", ranName)
// c.sendRicSubDelRequest(subID, requestSN, funcID)
return
}
@ -1166,8 +1162,8 @@ func (c *Control) setEventDeleteExpiredTimer(ranName string) {
delete(c.eventDeleteExpiredMap, ranName)
c.eventDeleteExpiredMu.Unlock()
if !isResponsed {
xapp.Logger.Debug("RIC_SUB_DEL_REQ[%s]: RIC Event Delete Timer expired!", ranName)
log.Printf("RIC_SUB_DEL_REQ[%s]: RIC Event Delete Timer expired!", ranName)
xapp.Logger.Debug("RIC_SUB_DEL_REQ[%s]: RIC Event Delete Timer experied!", ranName)
log.Printf("RIC_SUB_DEL_REQ[%s]: RIC Event Delete Timer experied!", ranName)
return
}
default:
@ -1247,7 +1243,7 @@ func (c *Control) sendRicSubRequest(subID int, requestSN int, funcID int) (err e
log.Printf("Set Payload: %x", params.Payload)
//params.Meid = &xapp.RMRMeid{RanName: c.ranList[index]}
params.Meid = &xapp.RMRMeid{PlmnID: "313131", EnbID: "::", RanName: "gnb_131_133_31000000"}
params.Meid = &xapp.RMRMeid{PlmnID: "373437", EnbID: "10110101110001100111011110001", RanName: "gnb_734_733_b5c67788"}
xapp.Logger.Debug("The RMR message to be sent is %d with SubId=%d", params.Mtype, params.SubId)
log.Printf("The RMR message to be sent is %d with SubId=%d", params.Mtype, params.SubId)
@ -1283,10 +1279,10 @@ func (c *Control) sendRicSubDelRequest(subID int, requestSN int, funcID int) (er
if funcID == 0 {
//params.Meid = &xapp.RMRMeid{PlmnID: "::", EnbID: "::", RanName: "0"}
params.Meid = &xapp.RMRMeid{PlmnID: "313131", EnbID: "::", RanName: "gnb_131_133_31000000"}
params.Meid = &xapp.RMRMeid{PlmnID: "373437", EnbID: "10110101110001100111011110001", RanName: "gnb_734_733_b5c67788"}
} else {
//params.Meid = &xapp.RMRMeid{PlmnID: "::", EnbID: "::", RanName: "3"}
params.Meid = &xapp.RMRMeid{PlmnID: "313131", EnbID: "::", RanName: "gnb_131_133_31000000"}
params.Meid = &xapp.RMRMeid{PlmnID: "373437", EnbID: "10110101110001100111011110001", RanName: "gnb_734_733_b5c67788"}
}
xapp.Logger.Debug("The RMR message to be sent is %d with SubId=%d", params.Mtype, params.SubId)
@ -1303,3 +1299,4 @@ func (c *Control) sendRicSubDelRequest(subID int, requestSN int, funcID int) (er
return nil
}

View File

@ -1,26 +0,0 @@
#!/bin/bash
#set -x
export CHART_REPO_URL=http://0.0.0.0:8090
dms_cli uninstall xappkpimon ricxapp
docker build . -f Dockerfile -t 127.0.0.1:5000/kpimon_master:1.0.0 # --no-cache
docker push 127.0.0.1:5000/kpimon_master:1.0.0
# dms_cli onboard config.json schema.json
dms_cli install xappkpimon 1.0.0 ricxapp
echo "Wait for 10 seconds"
sleep 10
unset $pod_name
pod_name=$(kubectl get pods -n ricxapp --no-headers -o custom-columns=":metadata.name")
echo kubectl exec -ti -n ricxapp $pod_name bash
# To run the kpimon
# ./kpimon -f /opt/ric/config/config-file.json

View File

@ -1,5 +0,0 @@
newrt|start
rte|20011|service-ricplt-a1mediator-rmr.ricplt:4562
rte|20012|service-ricplt-a1mediator-rmr.ricplt:4562
rte|12010|service-ricplt-submgr-rmr.ricplt:4560
newrt|end

View File

@ -5,8 +5,8 @@
{
"name": "xappkpimon",
"image": {
"registry": "127.0.0.1:5000",
"name": "kpimon_master",
"registry": "nexus3.o-ran-sc.org:10002",
"name": "o-ran-sc/scp-ric-app-kpimon",
"tag": "1.0.0"
}
}

View File

@ -1,41 +0,0 @@
{
"xapp_name": "xappkpimon",
"version": "1.0.0",
"containers": [
{
"name": "xappkpimon",
"image": {
"registry": "127.0.0.1:5000",
"name": "kpimon_sleep",
"tag": "1.0.0"
}
}
],
"messaging": {
"ports": [
{
"name": "rmr-data",
"container": "xappkpimon",
"port": 4560,
"rxMessages": ["RIC_SUB_RESP", "RIC_INDICATION"],
"txMessages": ["RIC_SUB_REQ"],
"policies": [],
"description": "rmr receive data port for xappkpimon"
},
{
"name": "rmr-route",
"container": "xappkpimon",
"port": 4561,
"description": "rmr route port for xappkpimon"
}
]
},
"rmr": {
"protPort": "tcp:4560",
"maxSize": 2072,
"numWorkers": 1,
"rxMessages": ["RIC_SUB_RESP", "RIC_INDICATION"],
"txMessages": ["RIC_SUB_REQ"],
"policies": []
}
}

View File

@ -1,62 +0,0 @@
{
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/root.json",
"type": "object",
"title": "The Root Schema",
"required": [
"active",
"interfaceId"
],
"properties": {
"active": {
"$id": "#/properties/active",
"type": "boolean",
"title": "The Active Schema",
"default": false,
"examples": [
false
]
},
"interfaceId": {
"$id": "#/properties/interfaceId",
"type": "object",
"title": "The Interfaceid Schema",
"required": [
"globalENBId"
],
"properties": {
"globalENBId": {
"$id": "#/properties/interfaceId/properties/globalENBId",
"type": "object",
"title": "The Globalenbid Schema",
"required": [
"plmnId",
"eNBId"
],
"properties": {
"plmnId": {
"$id": "#/properties/interfaceId/properties/globalENBId/properties/plmnId",
"type": "string",
"title": "The Plmnid Schema",
"default": "",
"examples": [
"310150"
],
"pattern": "^(.*)$"
},
"eNBId": {
"$id": "#/properties/interfaceId/properties/globalENBId/properties/eNBId",
"type": "integer",
"title": "The Enbid Schema",
"default": 0,
"examples": [
202251
]
}
}
}
}
}
}
}