Additions to measurements
[ric-plt/vespamgr.git] / cmd / vesmgr / config.go
old mode 100644 (file)
new mode 100755 (executable)
index 77b4ca8..b79d19b
  *  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 (
        "encoding/json"
+       "fmt"
        "io"
        "io/ioutil"
        "os"
@@ -31,6 +36,7 @@ import (
 
 const defaultReportingEntityID = "00000000-0000-0000-0000-000000000000"
 const defaultVNFName = "Vespa"
+const defaultNFNamingCode = "ricp"
 
 func readSystemUUID() string {
        data, err := ioutil.ReadFile("/sys/class/dmi/id/product_uuid")
@@ -48,6 +54,14 @@ func getVNFName() string {
        return VNFName
 }
 
+func getNFNamingCode() string {
+       NFNamingCode := os.Getenv("VESMGR_NFNAMINGCODE")
+       if NFNamingCode == "" {
+               return defaultNFNamingCode
+       }
+       return NFNamingCode
+}
+
 func basicVespaConf() VESAgentConfiguration {
        var vespaconf = VESAgentConfiguration{
                DataDir: "/tmp/data",
@@ -57,19 +71,10 @@ func basicVespaConf() VESAgentConfiguration {
                        ReportingEntityName: "Vespa",
                        ReportingEntityID:   readSystemUUID(),
                        MaxSize:             2000000,
-                       NfNamingCode:        "hsxp",
-                       NfcNamingCodes: []NfcNamingCode{
-                               NfcNamingCode{
-                                       Type:  "oam",
-                                       Vnfcs: []string{"lr-ope-0", "lr-ope-1", "lr-ope-2"},
-                               },
-                               NfcNamingCode{
-                                       Type:  "etl",
-                                       Vnfcs: []string{"lr-pro-0", "lr-pro-1"},
-                               },
-                       },
-                       RetryInterval: time.Second * 5,
-                       MaxMissed:     2,
+                       NfNamingCode:        getNFNamingCode(),
+                       NfcNamingCodes:      []NfcNamingCode{},
+                       RetryInterval:       time.Second * 5,
+                       MaxMissed:           2,
                },
                Measurement: MeasurementConfiguration{
                        // Domain abbreviation has to be set to “Mvfs” for VES 5.3,
@@ -92,8 +97,13 @@ func basicVespaConf() VESAgentConfiguration {
 
 // AppMetricsStruct contains xapplication metrics definition
 type AppMetricsStruct struct {
+       MoId           string
+       MeasType       string
+       MeasId         string
+       MeasInterval   string
        ObjectName     string
        ObjectInstance string
+       CounterId      string
 }
 
 // AppMetrics contains metrics definitions for all Xapps
@@ -104,11 +114,16 @@ type AppMetrics map[string]AppMetricsStruct
 //
 // { ...
 //   "config" : {
-//     "metrics": [
-//       { "name": "...", "objectName": "...", "objectInstamce": "..." },
+//        "measurements": [
+//      {
+//               "metrics": [
+//          { "name": "...", "objectName": "...", "objectInstamce": "..." },
+//           ...
+//         ]
+//       }
 //       ...
 //     ]
-//   }
+//    }
 // }
 func parseMetricsFromXAppDescriptor(descriptor []byte, appMetrics AppMetrics) AppMetrics {
        var desc []map[string]interface{}
@@ -116,11 +131,29 @@ func parseMetricsFromXAppDescriptor(descriptor []byte, appMetrics AppMetrics) Ap
 
        for _, app := range desc {
                config, configOk := app["config"]
-               if configOk {
-                       metrics, metricsOk := config.(map[string]interface{})["metrics"]
-                       if metricsOk {
-                               parseMetricsRules(metrics.([]interface{}), appMetrics)
+               if !configOk {
+                       logger.Info("No xApp config found!")
+                       continue
+               }
+               measurements, measurementsOk := config.(map[string]interface{})["measurements"]
+               if !measurementsOk {
+                       logger.Info("No xApp metrics found!")
+                       continue
+               }
+
+               for _, m := range measurements.([]interface{}) {
+                       moId, moIdOk := m.(map[string]interface{})["moId"].(string)
+                       measType, measTypeOk := m.(map[string]interface{})["measType"].(string)
+                       measId, measIdOk := m.(map[string]interface{})["measId"].(string)
+                       measInterval, measIntervalOk := m.(map[string]interface{})["measInterval"].(string)
+                       metrics, metricsOk := m.(map[string]interface{})["metrics"]
+                       if !metricsOk || !measTypeOk || !measIdOk || !moIdOk || !measIntervalOk {
+                               logger.Info("No metrics found for moId=%s measType=%s measId=%s measInterval=%s", moId, measId, measType, measInterval)
+                               continue
                        }
+                       logger.Info("Parsed measurement: moId=%s type=%s id=%s interval=%s", moId, measType, measId, measInterval)
+
+                       parseMetricsRules(metrics.([]interface{}), appMetrics, moId, measType, measId, measInterval)
                }
        }
        return appMetrics
@@ -130,16 +163,17 @@ func parseMetricsFromXAppDescriptor(descriptor []byte, appMetrics AppMetrics) Ap
 // of the following format:
 //    { "name": xxx, "objectName": yyy, "objectInstance": zzz }
 // Entries, which do not have all the necessary fields, are ignored.
-func parseMetricsRules(metricsMap []interface{}, appMetrics AppMetrics) AppMetrics {
+func parseMetricsRules(metricsMap []interface{}, appMetrics AppMetrics, moId, measType, measId, measInterval string) AppMetrics {
        for _, element := range metricsMap {
                name, nameOk := element.(map[string]interface{})["name"].(string)
                if nameOk {
                        _, alreadyFound := appMetrics[name]
                        objectName, objectNameOk := element.(map[string]interface{})["objectName"].(string)
                        objectInstance, objectInstanceOk := element.(map[string]interface{})["objectInstance"].(string)
-                       if !alreadyFound && objectNameOk && objectInstanceOk {
-                               appMetrics[name] = AppMetricsStruct{objectName, objectInstance}
-                               logger.Info("parsed counter %s %s %s", name, objectName, objectInstance)
+                       counterId, counterIdOk := element.(map[string]interface{})["counterId"].(string)
+                       if !alreadyFound && objectNameOk && objectInstanceOk && counterIdOk {
+                               appMetrics[name] = AppMetricsStruct{moId, measType, measId, measInterval, objectName, objectInstance, counterId}
+                               logger.Info("Parsed counter name=%s %s/%s  M%sC%s", name, objectName, objectInstance, measId, counterId)
                        }
                        if alreadyFound {
                                logger.Info("skipped duplicate counter %s", name)
@@ -149,35 +183,34 @@ func parseMetricsRules(metricsMap []interface{}, appMetrics AppMetrics) AppMetri
        return appMetrics
 }
 
-func getRules(vespaconf *VESAgentConfiguration, xAppConfig []byte) {
-       appMetrics := make(AppMetrics)
-       parseMetricsFromXAppDescriptor(xAppConfig, appMetrics)
-
-       makeRule := func(expr string, objName string, objInstance string) MetricRule {
+func getRules(vespaconf *VESAgentConfiguration, xAppConfig []byte) bool {
+       makeRule := func(expr string, value AppMetricsStruct) MetricRule {
                return MetricRule{
                        Target:         "AdditionalObjects",
                        Expr:           expr,
-                       ObjectInstance: objInstance,
-                       ObjectName:     objName,
+                       ObjectInstance: fmt.Sprintf("%s:%s", value.ObjectInstance, value.CounterId),
+                       ObjectName:     value.ObjectName,
                        ObjectKeys: []Label{
-                               Label{
-                                       Name: "ricComponentName",
-                                       Expr: "'{{.labels.kubernetes_name}}'",
-                               },
+                               {Name: "ricComponentName", Expr: "'{{.labels.kubernetes_name}}'"},
+                               {Name: "moId", Expr: value.MoId},
+                               {Name: "measType", Expr: value.MeasType},
+                               {Name: "measId", Expr: value.MeasId},
+                               {Name: "measInterval", Expr: value.MeasInterval},
                        },
                }
        }
-       var metricsMap map[string][]interface{}
-       json.Unmarshal(xAppConfig, &metricsMap)
-       metrics := parseMetricsRules(metricsMap["metrics"], appMetrics)
+       appMetrics := make(AppMetrics)
+       metrics := parseMetricsFromXAppDescriptor(xAppConfig, appMetrics)
 
        vespaconf.Measurement.Prometheus.Rules.Metrics = make([]MetricRule, 0, len(metrics))
        for key, value := range metrics {
-               vespaconf.Measurement.Prometheus.Rules.Metrics = append(vespaconf.Measurement.Prometheus.Rules.Metrics, makeRule(key, value.ObjectName, value.ObjectInstance))
+               vespaconf.Measurement.Prometheus.Rules.Metrics = append(vespaconf.Measurement.Prometheus.Rules.Metrics, makeRule(key, value))
        }
        if len(vespaconf.Measurement.Prometheus.Rules.Metrics) == 0 {
                logger.Info("vespa config with empty metrics")
        }
+
+       return len(vespaconf.Measurement.Prometheus.Rules.Metrics) > 0
 }
 
 func getCollectorConfiguration(vespaconf *VESAgentConfiguration) {
@@ -188,12 +221,14 @@ func getCollectorConfiguration(vespaconf *VESAgentConfiguration) {
        vespaconf.PrimaryCollector.ServerRoot = os.Getenv("VESMGR_PRICOLLECTOR_SERVERROOT")
        vespaconf.PrimaryCollector.Topic = os.Getenv("VESMGR_PRICOLLECTOR_TOPIC")
        portStr := os.Getenv("VESMGR_PRICOLLECTOR_PORT")
+
        if portStr == "" {
                vespaconf.PrimaryCollector.Port = 8443
        } else {
                port, _ := strconv.Atoi(portStr)
                vespaconf.PrimaryCollector.Port = port
        }
+
        secureStr := os.Getenv("VESMGR_PRICOLLECTOR_SECURE")
        if secureStr == "true" {
                vespaconf.PrimaryCollector.Secure = true
@@ -204,8 +239,11 @@ func getCollectorConfiguration(vespaconf *VESAgentConfiguration) {
 
 func createVespaConfig(writer io.Writer, xAppStatus []byte) {
        vespaconf := basicVespaConf()
+
        getRules(&vespaconf, xAppStatus)
+
        getCollectorConfiguration(&vespaconf)
+
        err := yaml.NewEncoder(writer).Encode(vespaconf)
        if err != nil {
                logger.Error("Cannot write vespa conf file: %s", err.Error())