X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=cmd%2Fvesmgr%2Fconfig.go;h=0df132b8a17d677549d433abd0efb4fc74ffa992;hb=364295fa6c8aa7b0aec4efe8ae8ce8241d03966c;hp=7c4a2dcb3bd53e1fba8e089e1cb974adec73eebd;hpb=66b7813221b6da5c15da40953d09d3846a4bc029;p=ric-plt%2Fvespamgr.git diff --git a/cmd/vesmgr/config.go b/cmd/vesmgr/config.go index 7c4a2dc..0df132b 100644 --- a/cmd/vesmgr/config.go +++ b/cmd/vesmgr/config.go @@ -18,43 +18,69 @@ package main import ( - "gopkg.in/yaml.v2" - "time" + "encoding/json" "io" + "io/ioutil" "os" "strconv" + "strings" + "time" + + "gopkg.in/yaml.v2" ) +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") + if err != nil { + return defaultReportingEntityID + } + return strings.TrimSpace(string(data)) +} + +func getVNFName() string { + VNFName := os.Getenv("VESMGR_VNFNAME") + if VNFName == "" { + return defaultVNFName + } + return VNFName +} + +func getNFNamingCode() string { + NFNamingCode := os.Getenv("VESMGR_NFNAMINGCODE") + if NFNamingCode == "" { + return defaultNFNamingCode + } + return NFNamingCode +} + func basicVespaConf() VESAgentConfiguration { - var vespaconf = VESAgentConfiguration { + var vespaconf = VESAgentConfiguration{ DataDir: "/tmp/data", Debug: false, - Event: EventConfiguration { - VNFName: "vespa-demo", // XXX - ReportingEntityID: "1af5bfa9-40b4-4522-b045-40e54f0310f", // XXX - 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"}, - }, - }, + Event: EventConfiguration{ + VNFName: getVNFName(), + ReportingEntityName: "Vespa", + ReportingEntityID: readSystemUUID(), + MaxSize: 2000000, + NfNamingCode: getNFNamingCode(), + NfcNamingCodes: []NfcNamingCode{}, RetryInterval: time.Second * 5, - MaxMissed: 2, + MaxMissed: 2, }, - Measurement: MeasurementConfiguration { - DomainAbbreviation: "Mvfs", + Measurement: MeasurementConfiguration{ + // Domain abbreviation has to be set to “Mvfs” for VES 5.3, + // and to “Measurement” for later VES interface versions. + DomainAbbreviation: "Mvfs", MaxBufferingDuration: time.Hour, - Prometheus: PrometheusConfig { - Timeout: time.Second * 30, + Prometheus: PrometheusConfig{ + Timeout: time.Second * 30, KeepAlive: time.Second * 30, - Rules: MetricRules { - DefaultValues: &MetricRule { + Rules: MetricRules{ + DefaultValues: &MetricRule{ VMIDLabel: "'{{.labels.instance}}'", }, }, @@ -64,32 +90,94 @@ func basicVespaConf() VESAgentConfiguration { return vespaconf } -func getRules(vespaconf *VESAgentConfiguration) { - // XXX - makeRule := func(expr string, obj_name string, obj_instance string) MetricRule { - return MetricRule { - Target: "AdditionalObjects", - Expr: expr, - ObjectInstance: obj_instance, - ObjectName: obj_name, - ObjectKeys: [] Label { - Label { +// AppMetricsStruct contains xapplication metrics definition +type AppMetricsStruct struct { + ObjectName string + ObjectInstance string +} + +// AppMetrics contains metrics definitions for all Xapps +type AppMetrics map[string]AppMetricsStruct + +// Parses the metrics data from an array of bytes, which is expected to contain a JSON +// array with structs of the following format: +// +// { ... +// "config" : { +// "metrics": [ +// { "name": "...", "objectName": "...", "objectInstamce": "..." }, +// ... +// ] +// } +// } +func parseMetricsFromXAppDescriptor(descriptor []byte, appMetrics AppMetrics) AppMetrics { + var desc []map[string]interface{} + json.Unmarshal(descriptor, &desc) + + for _, app := range desc { + config, configOk := app["config"] + if configOk { + metrics, metricsOk := config.(map[string]interface{})["metrics"] + if metricsOk { + parseMetricsRules(metrics.([]interface{}), appMetrics) + } + } + } + return appMetrics +} + +// Parses the metrics data from an array of interfaces, which are expected to be maps +// 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 { + 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) + } + if alreadyFound { + logger.Info("skipped duplicate counter %s", name) + } + } + } + return appMetrics +} + +func getRules(vespaconf *VESAgentConfiguration, xAppConfig []byte) { + appMetrics := make(AppMetrics) + parseMetricsFromXAppDescriptor(xAppConfig, appMetrics) + + makeRule := func(expr string, objName string, objInstance string) MetricRule { + return MetricRule{ + Target: "AdditionalObjects", + Expr: expr, + ObjectInstance: objInstance, + ObjectName: objName, + ObjectKeys: []Label{ + Label{ Name: "ricComponentName", - Expr: "'{{.labels.app_kubernetes_io_instance}}'", + Expr: "'{{.labels.kubernetes_name}}'", }, }, } } - // Hard coded for now - vespaconf.Measurement.Prometheus.Rules.Metrics = []MetricRule { - makeRule("ricxapp_RMR_Received", "ricxappRMRreceivedCounter", "ricxappRMRReceived"), - makeRule("ricxapp_RMR_ReceiveError", "ricxappRMRReceiveErrorCounter", "ricxappRMRReceiveError"), - makeRule("ricxapp_RMR_Transmitted", "ricxappRMRTransmittedCounter", "ricxappRMRTransmitted"), - makeRule("ricxapp_RMR_TransmitError", "ricxappRMRTransmitErrorCounter", "ricxappRMRTransmitError"), - makeRule("ricxapp_SDL_Stored", "ricxappSDLStoredCounter", "ricxappSDLStored"), - makeRule("ricxapp_SDL_StoreError", "ricxappSDLStoreErrorCounter", "ricxappSDLStoreError"), - } + var metricsMap map[string][]interface{} + json.Unmarshal(xAppConfig, &metricsMap) + metrics := parseMetricsRules(metricsMap["metrics"], 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)) + } + if len(vespaconf.Measurement.Prometheus.Rules.Metrics) == 0 { + logger.Info("vespa config with empty metrics") + } } func getCollectorConfiguration(vespaconf *VESAgentConfiguration) { @@ -99,24 +187,24 @@ func getCollectorConfiguration(vespaconf *VESAgentConfiguration) { vespaconf.PrimaryCollector.FQDN = os.Getenv("VESMGR_PRICOLLECTOR_ADDR") vespaconf.PrimaryCollector.ServerRoot = os.Getenv("VESMGR_PRICOLLECTOR_SERVERROOT") vespaconf.PrimaryCollector.Topic = os.Getenv("VESMGR_PRICOLLECTOR_TOPIC") - port_str := os.Getenv("VESMGR_PRICOLLECTOR_PORT") - if port_str == "" { + portStr := os.Getenv("VESMGR_PRICOLLECTOR_PORT") + if portStr == "" { vespaconf.PrimaryCollector.Port = 8443 } else { - port, _ := strconv.Atoi(port_str) + port, _ := strconv.Atoi(portStr) vespaconf.PrimaryCollector.Port = port } - secure_str := os.Getenv("VESMGR_PRICOLLECTOR_SECURE") - if secure_str == "true" { + secureStr := os.Getenv("VESMGR_PRICOLLECTOR_SECURE") + if secureStr == "true" { vespaconf.PrimaryCollector.Secure = true } else { vespaconf.PrimaryCollector.Secure = false } } -func createVespaConfig(writer io.Writer) { +func createVespaConfig(writer io.Writer, xAppStatus []byte) { vespaconf := basicVespaConf() - getRules(&vespaconf) + getRules(&vespaconf, xAppStatus) getCollectorConfiguration(&vespaconf) err := yaml.NewEncoder(writer).Encode(vespaconf) if err != nil {