Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2019 AT&T Intellectual Property. |
| 3 | * Copyright (c) 2018-2019 Nokia. |
| 4 | * |
| 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 |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 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. |
| 16 | */ |
| 17 | |
| 18 | package main |
| 19 | |
| 20 | import ( |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 21 | "encoding/json" |
Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 22 | "io" |
Katri Turunen | 3e79fbe | 2019-09-26 12:46:07 +0300 | [diff] [blame] | 23 | "io/ioutil" |
Katri Turunen | 66b7813 | 2019-09-02 10:28:52 +0300 | [diff] [blame] | 24 | "os" |
| 25 | "strconv" |
Katri Turunen | 3e79fbe | 2019-09-26 12:46:07 +0300 | [diff] [blame] | 26 | "strings" |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 27 | "time" |
Roni Riska | fc77ebb | 2019-09-26 08:20:44 +0300 | [diff] [blame] | 28 | |
| 29 | "gopkg.in/yaml.v2" |
Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 30 | ) |
| 31 | |
Katri Turunen | 3e79fbe | 2019-09-26 12:46:07 +0300 | [diff] [blame] | 32 | const defaultReportingEntityID = "00000000-0000-0000-0000-000000000000" |
| 33 | const defaultVNFName = "Vespa" |
Roni Riska | 364295f | 2019-09-30 09:39:12 +0300 | [diff] [blame] | 34 | const defaultNFNamingCode = "ricp" |
Katri Turunen | 3e79fbe | 2019-09-26 12:46:07 +0300 | [diff] [blame] | 35 | |
| 36 | func readSystemUUID() string { |
| 37 | data, err := ioutil.ReadFile("/sys/class/dmi/id/product_uuid") |
| 38 | if err != nil { |
| 39 | return defaultReportingEntityID |
| 40 | } |
| 41 | return strings.TrimSpace(string(data)) |
| 42 | } |
| 43 | |
| 44 | func getVNFName() string { |
| 45 | VNFName := os.Getenv("VESMGR_VNFNAME") |
| 46 | if VNFName == "" { |
| 47 | return defaultVNFName |
| 48 | } |
| 49 | return VNFName |
| 50 | } |
| 51 | |
Roni Riska | 364295f | 2019-09-30 09:39:12 +0300 | [diff] [blame] | 52 | func getNFNamingCode() string { |
| 53 | NFNamingCode := os.Getenv("VESMGR_NFNAMINGCODE") |
| 54 | if NFNamingCode == "" { |
| 55 | return defaultNFNamingCode |
| 56 | } |
| 57 | return NFNamingCode |
| 58 | } |
| 59 | |
Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 60 | func basicVespaConf() VESAgentConfiguration { |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 61 | var vespaconf = VESAgentConfiguration{ |
Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 62 | DataDir: "/tmp/data", |
| 63 | Debug: false, |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 64 | Event: EventConfiguration{ |
Katri Turunen | 3e79fbe | 2019-09-26 12:46:07 +0300 | [diff] [blame] | 65 | VNFName: getVNFName(), |
| 66 | ReportingEntityName: "Vespa", |
| 67 | ReportingEntityID: readSystemUUID(), |
| 68 | MaxSize: 2000000, |
Roni Riska | 364295f | 2019-09-30 09:39:12 +0300 | [diff] [blame] | 69 | NfNamingCode: getNFNamingCode(), |
| 70 | NfcNamingCodes: []NfcNamingCode{}, |
Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 71 | RetryInterval: time.Second * 5, |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 72 | MaxMissed: 2, |
Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 73 | }, |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 74 | Measurement: MeasurementConfiguration{ |
Katri Turunen | 3e79fbe | 2019-09-26 12:46:07 +0300 | [diff] [blame] | 75 | // Domain abbreviation has to be set to “Mvfs” for VES 5.3, |
| 76 | // and to “Measurement” for later VES interface versions. |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 77 | DomainAbbreviation: "Mvfs", |
Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 78 | MaxBufferingDuration: time.Hour, |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 79 | Prometheus: PrometheusConfig{ |
| 80 | Timeout: time.Second * 30, |
Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 81 | KeepAlive: time.Second * 30, |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 82 | Rules: MetricRules{ |
| 83 | DefaultValues: &MetricRule{ |
Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 84 | VMIDLabel: "'{{.labels.instance}}'", |
| 85 | }, |
| 86 | }, |
| 87 | }, |
| 88 | }, |
| 89 | } |
| 90 | return vespaconf |
| 91 | } |
| 92 | |
Roni Riska | fc77ebb | 2019-09-26 08:20:44 +0300 | [diff] [blame] | 93 | // AppMetricsStruct contains xapplication metrics definition |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 94 | type AppMetricsStruct struct { |
| 95 | ObjectName string |
| 96 | ObjectInstance string |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 97 | } |
| 98 | |
Roni Riska | fc77ebb | 2019-09-26 08:20:44 +0300 | [diff] [blame] | 99 | // AppMetrics contains metrics definitions for all Xapps |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 100 | type AppMetrics map[string]AppMetricsStruct |
| 101 | |
| 102 | // Parses the metrics data from an array of bytes, which is expected to contain a JSON |
| 103 | // array with structs of the following format: |
| 104 | // |
| 105 | // { ... |
| 106 | // "config" : { |
| 107 | // "metrics": [ |
| 108 | // { "name": "...", "objectName": "...", "objectInstamce": "..." }, |
| 109 | // ... |
| 110 | // ] |
| 111 | // } |
| 112 | // } |
| 113 | func parseMetricsFromXAppDescriptor(descriptor []byte, appMetrics AppMetrics) AppMetrics { |
| 114 | var desc []map[string]interface{} |
| 115 | json.Unmarshal(descriptor, &desc) |
| 116 | |
| 117 | for _, app := range desc { |
Roni Riska | fc77ebb | 2019-09-26 08:20:44 +0300 | [diff] [blame] | 118 | config, configOk := app["config"] |
| 119 | if configOk { |
| 120 | metrics, metricsOk := config.(map[string]interface{})["metrics"] |
| 121 | if metricsOk { |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 122 | parseMetricsRules(metrics.([]interface{}), appMetrics) |
| 123 | } |
| 124 | } |
| 125 | } |
| 126 | return appMetrics |
| 127 | } |
| 128 | |
| 129 | // Parses the metrics data from an array of interfaces, which are expected to be maps |
| 130 | // of the following format: |
| 131 | // { "name": xxx, "objectName": yyy, "objectInstance": zzz } |
| 132 | // Entries, which do not have all the necessary fields, are ignored. |
| 133 | func parseMetricsRules(metricsMap []interface{}, appMetrics AppMetrics) AppMetrics { |
| 134 | for _, element := range metricsMap { |
Roni Riska | fc77ebb | 2019-09-26 08:20:44 +0300 | [diff] [blame] | 135 | name, nameOk := element.(map[string]interface{})["name"].(string) |
| 136 | if nameOk { |
| 137 | _, alreadyFound := appMetrics[name] |
| 138 | objectName, objectNameOk := element.(map[string]interface{})["objectName"].(string) |
| 139 | objectInstance, objectInstanceOk := element.(map[string]interface{})["objectInstance"].(string) |
| 140 | if !alreadyFound && objectNameOk && objectInstanceOk { |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 141 | appMetrics[name] = AppMetricsStruct{objectName, objectInstance} |
| 142 | logger.Info("parsed counter %s %s %s", name, objectName, objectInstance) |
| 143 | } |
Roni Riska | fc77ebb | 2019-09-26 08:20:44 +0300 | [diff] [blame] | 144 | if alreadyFound { |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 145 | logger.Info("skipped duplicate counter %s", name) |
| 146 | } |
| 147 | } |
| 148 | } |
| 149 | return appMetrics |
| 150 | } |
| 151 | |
| 152 | func getRules(vespaconf *VESAgentConfiguration, xAppConfig []byte) { |
| 153 | appMetrics := make(AppMetrics) |
| 154 | parseMetricsFromXAppDescriptor(xAppConfig, appMetrics) |
| 155 | |
Roni Riska | fc77ebb | 2019-09-26 08:20:44 +0300 | [diff] [blame] | 156 | makeRule := func(expr string, objName string, objInstance string) MetricRule { |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 157 | return MetricRule{ |
| 158 | Target: "AdditionalObjects", |
| 159 | Expr: expr, |
Roni Riska | fc77ebb | 2019-09-26 08:20:44 +0300 | [diff] [blame] | 160 | ObjectInstance: objInstance, |
| 161 | ObjectName: objName, |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 162 | ObjectKeys: []Label{ |
| 163 | Label{ |
Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 164 | Name: "ricComponentName", |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 165 | Expr: "'{{.labels.kubernetes_name}}'", |
Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 166 | }, |
| 167 | }, |
| 168 | } |
| 169 | } |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 170 | var metricsMap map[string][]interface{} |
| 171 | json.Unmarshal(xAppConfig, &metricsMap) |
| 172 | metrics := parseMetricsRules(metricsMap["metrics"], appMetrics) |
Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 173 | |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 174 | vespaconf.Measurement.Prometheus.Rules.Metrics = make([]MetricRule, 0, len(metrics)) |
| 175 | for key, value := range metrics { |
| 176 | vespaconf.Measurement.Prometheus.Rules.Metrics = append(vespaconf.Measurement.Prometheus.Rules.Metrics, makeRule(key, value.ObjectName, value.ObjectInstance)) |
| 177 | } |
| 178 | if len(vespaconf.Measurement.Prometheus.Rules.Metrics) == 0 { |
| 179 | logger.Info("vespa config with empty metrics") |
| 180 | } |
Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 181 | } |
| 182 | |
Katri Turunen | 66b7813 | 2019-09-02 10:28:52 +0300 | [diff] [blame] | 183 | func getCollectorConfiguration(vespaconf *VESAgentConfiguration) { |
| 184 | vespaconf.PrimaryCollector.User = os.Getenv("VESMGR_PRICOLLECTOR_USER") |
| 185 | vespaconf.PrimaryCollector.Password = os.Getenv("VESMGR_PRICOLLECTOR_PASSWORD") |
| 186 | vespaconf.PrimaryCollector.PassPhrase = os.Getenv("VESMGR_PRICOLLECTOR_PASSPHRASE") |
| 187 | vespaconf.PrimaryCollector.FQDN = os.Getenv("VESMGR_PRICOLLECTOR_ADDR") |
| 188 | vespaconf.PrimaryCollector.ServerRoot = os.Getenv("VESMGR_PRICOLLECTOR_SERVERROOT") |
| 189 | vespaconf.PrimaryCollector.Topic = os.Getenv("VESMGR_PRICOLLECTOR_TOPIC") |
Roni Riska | fc77ebb | 2019-09-26 08:20:44 +0300 | [diff] [blame] | 190 | portStr := os.Getenv("VESMGR_PRICOLLECTOR_PORT") |
| 191 | if portStr == "" { |
Katri Turunen | 66b7813 | 2019-09-02 10:28:52 +0300 | [diff] [blame] | 192 | vespaconf.PrimaryCollector.Port = 8443 |
| 193 | } else { |
Roni Riska | fc77ebb | 2019-09-26 08:20:44 +0300 | [diff] [blame] | 194 | port, _ := strconv.Atoi(portStr) |
Katri Turunen | 66b7813 | 2019-09-02 10:28:52 +0300 | [diff] [blame] | 195 | vespaconf.PrimaryCollector.Port = port |
| 196 | } |
Roni Riska | fc77ebb | 2019-09-26 08:20:44 +0300 | [diff] [blame] | 197 | secureStr := os.Getenv("VESMGR_PRICOLLECTOR_SECURE") |
| 198 | if secureStr == "true" { |
Katri Turunen | 66b7813 | 2019-09-02 10:28:52 +0300 | [diff] [blame] | 199 | vespaconf.PrimaryCollector.Secure = true |
| 200 | } else { |
| 201 | vespaconf.PrimaryCollector.Secure = false |
| 202 | } |
| 203 | } |
| 204 | |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 205 | func createVespaConfig(writer io.Writer, xAppStatus []byte) { |
Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 206 | vespaconf := basicVespaConf() |
Katri Turunen | 412df96 | 2019-09-16 08:48:18 +0300 | [diff] [blame] | 207 | getRules(&vespaconf, xAppStatus) |
Katri Turunen | 66b7813 | 2019-09-02 10:28:52 +0300 | [diff] [blame] | 208 | getCollectorConfiguration(&vespaconf) |
Katri Turunen | 4b74f01 | 2019-08-15 10:49:36 +0300 | [diff] [blame] | 209 | err := yaml.NewEncoder(writer).Encode(vespaconf) |
| 210 | if err != nil { |
| 211 | logger.Error("Cannot write vespa conf file: %s", err.Error()) |
| 212 | return |
| 213 | } |
Katri Turunen | 66b7813 | 2019-09-02 10:28:52 +0300 | [diff] [blame] | 214 | } |