Refactor the code
[ric-plt/vespamgr.git] / cmd / vesmgr / config.go
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 (
21         "encoding/json"
22         "io"
23         "os"
24         "strconv"
25         "time"
26
27         "gopkg.in/yaml.v2"
28 )
29
30 func basicVespaConf() VESAgentConfiguration {
31         var vespaconf = VESAgentConfiguration{
32                 DataDir: "/tmp/data",
33                 Debug:   false,
34                 Event: EventConfiguration{
35                         VNFName:           "vespa-demo",                          // XXX
36                         ReportingEntityID: "1af5bfa9-40b4-4522-b045-40e54f0310f", // XXX
37                         MaxSize:           2000000,
38                         NfNamingCode:      "hsxp",
39                         NfcNamingCodes: []NfcNamingCode{
40                                 NfcNamingCode{
41                                         Type:  "oam",
42                                         Vnfcs: []string{"lr-ope-0", "lr-ope-1", "lr-ope-2"},
43                                 },
44                                 NfcNamingCode{
45                                         Type:  "etl",
46                                         Vnfcs: []string{"lr-pro-0", "lr-pro-1"},
47                                 },
48                         },
49                         RetryInterval: time.Second * 5,
50                         MaxMissed:     2,
51                 },
52                 Measurement: MeasurementConfiguration{
53                         DomainAbbreviation:   "Mvfs",
54                         MaxBufferingDuration: time.Hour,
55                         Prometheus: PrometheusConfig{
56                                 Timeout:   time.Second * 30,
57                                 KeepAlive: time.Second * 30,
58                                 Rules: MetricRules{
59                                         DefaultValues: &MetricRule{
60                                                 VMIDLabel: "'{{.labels.instance}}'",
61                                         },
62                                 },
63                         },
64                 },
65         }
66         return vespaconf
67 }
68
69 // AppMetricsStruct contains xapplication metrics definition
70 type AppMetricsStruct struct {
71         ObjectName     string
72         ObjectInstance string
73 }
74
75 // AppMetrics contains metrics definitions for all Xapps
76 type AppMetrics map[string]AppMetricsStruct
77
78 // Parses the metrics data from an array of bytes, which is expected to contain a JSON
79 // array with structs of the following format:
80 //
81 // { ...
82 //   "config" : {
83 //     "metrics": [
84 //       { "name": "...", "objectName": "...", "objectInstamce": "..." },
85 //       ...
86 //     ]
87 //   }
88 // }
89 func parseMetricsFromXAppDescriptor(descriptor []byte, appMetrics AppMetrics) AppMetrics {
90         var desc []map[string]interface{}
91         json.Unmarshal(descriptor, &desc)
92
93         for _, app := range desc {
94                 config, configOk := app["config"]
95                 if configOk {
96                         metrics, metricsOk := config.(map[string]interface{})["metrics"]
97                         if metricsOk {
98                                 parseMetricsRules(metrics.([]interface{}), appMetrics)
99                         }
100                 }
101         }
102         return appMetrics
103 }
104
105 // Parses the metrics data from an array of interfaces, which are expected to be maps
106 // of the following format:
107 //    { "name": xxx, "objectName": yyy, "objectInstance": zzz }
108 // Entries, which do not have all the necessary fields, are ignored.
109 func parseMetricsRules(metricsMap []interface{}, appMetrics AppMetrics) AppMetrics {
110         for _, element := range metricsMap {
111                 name, nameOk := element.(map[string]interface{})["name"].(string)
112                 if nameOk {
113                         _, alreadyFound := appMetrics[name]
114                         objectName, objectNameOk := element.(map[string]interface{})["objectName"].(string)
115                         objectInstance, objectInstanceOk := element.(map[string]interface{})["objectInstance"].(string)
116                         if !alreadyFound && objectNameOk && objectInstanceOk {
117                                 appMetrics[name] = AppMetricsStruct{objectName, objectInstance}
118                                 logger.Info("parsed counter %s %s %s", name, objectName, objectInstance)
119                         }
120                         if alreadyFound {
121                                 logger.Info("skipped duplicate counter %s", name)
122                         }
123                 }
124         }
125         return appMetrics
126 }
127
128 func getRules(vespaconf *VESAgentConfiguration, xAppConfig []byte) {
129         appMetrics := make(AppMetrics)
130         parseMetricsFromXAppDescriptor(xAppConfig, appMetrics)
131
132         makeRule := func(expr string, objName string, objInstance string) MetricRule {
133                 return MetricRule{
134                         Target:         "AdditionalObjects",
135                         Expr:           expr,
136                         ObjectInstance: objInstance,
137                         ObjectName:     objName,
138                         ObjectKeys: []Label{
139                                 Label{
140                                         Name: "ricComponentName",
141                                         Expr: "'{{.labels.kubernetes_name}}'",
142                                 },
143                         },
144                 }
145         }
146         var metricsMap map[string][]interface{}
147         json.Unmarshal(xAppConfig, &metricsMap)
148         metrics := parseMetricsRules(metricsMap["metrics"], appMetrics)
149
150         vespaconf.Measurement.Prometheus.Rules.Metrics = make([]MetricRule, 0, len(metrics))
151         for key, value := range metrics {
152                 vespaconf.Measurement.Prometheus.Rules.Metrics = append(vespaconf.Measurement.Prometheus.Rules.Metrics, makeRule(key, value.ObjectName, value.ObjectInstance))
153         }
154         if len(vespaconf.Measurement.Prometheus.Rules.Metrics) == 0 {
155                 logger.Info("vespa config with empty metrics")
156         }
157 }
158
159 func getCollectorConfiguration(vespaconf *VESAgentConfiguration) {
160         vespaconf.PrimaryCollector.User = os.Getenv("VESMGR_PRICOLLECTOR_USER")
161         vespaconf.PrimaryCollector.Password = os.Getenv("VESMGR_PRICOLLECTOR_PASSWORD")
162         vespaconf.PrimaryCollector.PassPhrase = os.Getenv("VESMGR_PRICOLLECTOR_PASSPHRASE")
163         vespaconf.PrimaryCollector.FQDN = os.Getenv("VESMGR_PRICOLLECTOR_ADDR")
164         vespaconf.PrimaryCollector.ServerRoot = os.Getenv("VESMGR_PRICOLLECTOR_SERVERROOT")
165         vespaconf.PrimaryCollector.Topic = os.Getenv("VESMGR_PRICOLLECTOR_TOPIC")
166         portStr := os.Getenv("VESMGR_PRICOLLECTOR_PORT")
167         if portStr == "" {
168                 vespaconf.PrimaryCollector.Port = 8443
169         } else {
170                 port, _ := strconv.Atoi(portStr)
171                 vespaconf.PrimaryCollector.Port = port
172         }
173         secureStr := os.Getenv("VESMGR_PRICOLLECTOR_SECURE")
174         if secureStr == "true" {
175                 vespaconf.PrimaryCollector.Secure = true
176         } else {
177                 vespaconf.PrimaryCollector.Secure = false
178         }
179 }
180
181 func createVespaConfig(writer io.Writer, xAppStatus []byte) {
182         vespaconf := basicVespaConf()
183         getRules(&vespaconf, xAppStatus)
184         getCollectorConfiguration(&vespaconf)
185         err := yaml.NewEncoder(writer).Encode(vespaconf)
186         if err != nil {
187                 logger.Error("Cannot write vespa conf file: %s", err.Error())
188                 return
189         }
190 }