2 * Copyright (c) 2019 AT&T Intellectual Property.
3 * Copyright (c) 2018-2019 Nokia.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * This source code is part of the near-RT RIC (RAN Intelligent Controller)
18 * platform project (RICP).
36 const defaultReportingEntityID = "00000000-0000-0000-0000-000000000000"
37 const defaultVNFName = "Vespa"
38 const defaultNFNamingCode = "ricp"
40 func readSystemUUID() string {
41 data, err := ioutil.ReadFile("/sys/class/dmi/id/product_uuid")
43 return defaultReportingEntityID
45 return strings.TrimSpace(string(data))
48 func getVNFName() string {
49 VNFName := os.Getenv("VESMGR_VNFNAME")
56 func getNFNamingCode() string {
57 NFNamingCode := os.Getenv("VESMGR_NFNAMINGCODE")
58 if NFNamingCode == "" {
59 return defaultNFNamingCode
64 func basicVespaConf() VESAgentConfiguration {
65 var vespaconf = VESAgentConfiguration{
68 Event: EventConfiguration{
69 VNFName: getVNFName(),
70 ReportingEntityName: "Vespa",
71 ReportingEntityID: readSystemUUID(),
73 NfNamingCode: getNFNamingCode(),
74 NfcNamingCodes: []NfcNamingCode{},
75 RetryInterval: time.Second * 5,
78 Measurement: MeasurementConfiguration{
79 // Domain abbreviation has to be set to “Mvfs” for VES 5.3,
80 // and to “Measurement” for later VES interface versions.
81 DomainAbbreviation: "Mvfs",
82 MaxBufferingDuration: time.Hour,
83 Prometheus: PrometheusConfig{
84 Timeout: time.Second * 30,
85 KeepAlive: time.Second * 30,
87 DefaultValues: &MetricRule{
88 VMIDLabel: "'{{.labels.instance}}'",
97 // AppMetricsStruct contains xapplication metrics definition
98 type AppMetricsStruct struct {
100 ObjectInstance string
105 // AppMetrics contains metrics definitions for all Xapps
106 type AppMetrics map[string]AppMetricsStruct
108 // Parses the metrics data from an array of bytes, which is expected to contain a JSON
109 // array with structs of the following format:
116 // { "name": "...", "objectName": "...", "objectInstamce": "..." },
124 func parseMetricsFromXAppDescriptor(descriptor []byte, appMetrics AppMetrics) AppMetrics {
125 var desc []map[string]interface{}
126 json.Unmarshal(descriptor, &desc)
128 for _, app := range desc {
129 config, configOk := app["config"]
131 logger.Info("No xApp config found!")
134 measurements, measurementsOk := config.(map[string]interface{})["measurements"]
136 logger.Info("No xApp metrics found!")
140 for _, m := range measurements.([]interface{}) {
141 measId, measIdOk := m.(map[string]interface{})["measId"].(string)
142 measObject, objectOk := m.(map[string]interface{})["object"].(string)
143 metrics, metricsOk := m.(map[string]interface{})["metrics"]
144 if !metricsOk || !measIdOk || !objectOk {
145 logger.Info("No metrics found for measId=%s Object=%s", measId, measObject)
148 parseMetricsRules(metrics.([]interface{}), appMetrics, measId, measObject)
154 // Parses the metrics data from an array of interfaces, which are expected to be maps
155 // of the following format:
156 // { "name": xxx, "objectName": yyy, "objectInstance": zzz }
157 // Entries, which do not have all the necessary fields, are ignored.
158 func parseMetricsRules(metricsMap []interface{}, appMetrics AppMetrics, measId, measObject string) AppMetrics {
159 for _, element := range metricsMap {
160 name, nameOk := element.(map[string]interface{})["name"].(string)
162 _, alreadyFound := appMetrics[name]
163 objectName, objectNameOk := element.(map[string]interface{})["objectName"].(string)
164 objectInstance, objectInstanceOk := element.(map[string]interface{})["objectInstance"].(string)
165 if !alreadyFound && objectNameOk && objectInstanceOk {
166 appMetrics[name] = AppMetricsStruct{objectName, objectInstance, measId, measObject}
167 logger.Info("parsed counter %s %s %s", name, objectName, objectInstance)
170 logger.Info("skipped duplicate counter %s", name)
177 func getRules(vespaconf *VESAgentConfiguration, xAppConfig []byte) {
178 makeRule := func(expr string, value AppMetricsStruct) MetricRule {
180 Target: "AdditionalObjects",
182 ObjectInstance: value.ObjectInstance,
183 ObjectName: value.ObjectName,
186 Name: "ricComponentName",
187 Expr: "'{{.labels.kubernetes_name}}'",
191 Expr: value.MeasObject,
200 appMetrics := make(AppMetrics)
201 metrics := parseMetricsFromXAppDescriptor(xAppConfig, appMetrics)
203 vespaconf.Measurement.Prometheus.Rules.Metrics = make([]MetricRule, 0, len(metrics))
204 for key, value := range metrics {
205 vespaconf.Measurement.Prometheus.Rules.Metrics = append(vespaconf.Measurement.Prometheus.Rules.Metrics, makeRule(key, value))
207 if len(vespaconf.Measurement.Prometheus.Rules.Metrics) == 0 {
208 logger.Info("vespa config with empty metrics")
212 func getCollectorConfiguration(vespaconf *VESAgentConfiguration) {
213 vespaconf.PrimaryCollector.User = os.Getenv("VESMGR_PRICOLLECTOR_USER")
214 vespaconf.PrimaryCollector.Password = os.Getenv("VESMGR_PRICOLLECTOR_PASSWORD")
215 vespaconf.PrimaryCollector.PassPhrase = os.Getenv("VESMGR_PRICOLLECTOR_PASSPHRASE")
216 vespaconf.PrimaryCollector.FQDN = os.Getenv("VESMGR_PRICOLLECTOR_ADDR")
217 vespaconf.PrimaryCollector.ServerRoot = os.Getenv("VESMGR_PRICOLLECTOR_SERVERROOT")
218 vespaconf.PrimaryCollector.Topic = os.Getenv("VESMGR_PRICOLLECTOR_TOPIC")
219 portStr := os.Getenv("VESMGR_PRICOLLECTOR_PORT")
221 vespaconf.PrimaryCollector.Port = 8443
223 port, _ := strconv.Atoi(portStr)
224 vespaconf.PrimaryCollector.Port = port
226 secureStr := os.Getenv("VESMGR_PRICOLLECTOR_SECURE")
227 if secureStr == "true" {
228 vespaconf.PrimaryCollector.Secure = true
230 vespaconf.PrimaryCollector.Secure = false
234 func createVespaConfig(writer io.Writer, xAppStatus []byte) {
235 vespaconf := basicVespaConf()
236 getRules(&vespaconf, xAppStatus)
237 getCollectorConfiguration(&vespaconf)
238 err := yaml.NewEncoder(writer).Encode(vespaconf)
240 logger.Error("Cannot write vespa conf file: %s", err.Error())