blob: 39a5df09ea587510f619cc37004a792da048999f [file] [log] [blame]
Jian Li69600e02018-12-24 13:21:18 +09001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.openstacktelemetry.impl;
17
18import com.google.common.collect.ImmutableMap;
19import com.google.common.collect.Lists;
20import com.google.common.collect.Maps;
21import org.apache.commons.configuration.ConfigurationException;
22import org.apache.commons.configuration.HierarchicalConfiguration;
23import org.apache.commons.configuration.XMLConfiguration;
24import org.onosproject.openstacktelemetry.api.config.TelemetryConfig;
25
26import java.io.IOException;
27import java.io.InputStream;
28import java.util.Arrays;
29import java.util.List;
30import java.util.Map;
31import java.util.stream.Collectors;
32
33import static org.onosproject.openstacktelemetry.api.config.TelemetryConfig.ConfigType.GRPC;
34import static org.onosproject.openstacktelemetry.api.config.TelemetryConfig.ConfigType.INFLUXDB;
35import static org.onosproject.openstacktelemetry.api.config.TelemetryConfig.ConfigType.KAFKA;
36import static org.onosproject.openstacktelemetry.api.config.TelemetryConfig.ConfigType.PROMETHEUS;
37import static org.onosproject.openstacktelemetry.api.config.TelemetryConfig.ConfigType.REST;
38import static org.onosproject.openstacktelemetry.api.config.TelemetryConfig.ConfigType.UNKNOWN;
39
40/**
41 * Utility capable of reading telemetry configuration XML resources and producing
42 * a telemetry config as a result.
43 * <p>
44 * The telemetry configurations stream structure is as follows:
45 * </p>
46 * <pre>
47 * &lt;configs&gt;
48 * &lt;config name=“...” [manufacturer="..." swVersion="..."]&gt;
49 * [&lt;property name=“key”&gt;value&lt;/key&gt;]
50 * ...
51 * &lt;/config&gt;
52 * ...
53 * &lt;/configs&gt;
54 * </pre>
55 */
56public class XmlTelemetryConfigLoader {
57
58 private static final String CONFIGS = "configs";
59 private static final String CONFIG = "config";
60
61 private static final String PROPERTY = "property";
62
63 private static final String TRUE = "true";
64
65 private static final String NAME = "[@name]";
66 private static final String TYPE = "[@type]";
67 private static final String EXTENDS = "[@extends]";
68 private static final String MFG = "[@manufacturer]";
69 private static final String SW = "[@swVersion]";
70 private static final String ENABLED = "[@enabled]";
71
72 private Map<String, TelemetryConfig> configs = Maps.newHashMap();
73
74 /**
75 * Creates a new config loader capable of loading configs from the supplied
76 * class loader.
77 */
78 public XmlTelemetryConfigLoader() {
79 }
80
81 /**
82 * Loads the specified telemetry configs resource as an XML stream and parses
83 * it to produce a ready-to-register config provider.
84 *
85 * @param configsStream stream containing the telemetry configs definition
86 * @return telemetry configuration provider
87 * @throws IOException if issues are encountered reading the stream
88 * or parsing the telemetry config definition within
89 */
90 public DefaultTelemetryConfigProvider
91 loadTelemetryConfigs(InputStream configsStream) throws IOException {
92 try {
93 XMLConfiguration cfg = new XMLConfiguration();
94 cfg.setRootElementName(CONFIGS);
95 cfg.setAttributeSplittingDisabled(true);
96
97 cfg.load(configsStream);
98 return loadTelemetryConfigs(cfg);
99 } catch (ConfigurationException e) {
100 throw new IOException("Unable to load telemetry configs", e);
101 }
102 }
103
104 /**
105 * Loads a telemetry config provider from the supplied hierarchical configuration.
106 *
107 * @param telemetryConfig hierarchical configuration containing the configs definition
108 * @return telemetry configuration provider
109 */
110 public DefaultTelemetryConfigProvider
111 loadTelemetryConfigs(HierarchicalConfiguration telemetryConfig) {
112 DefaultTelemetryConfigProvider provider = new DefaultTelemetryConfigProvider();
113 for (HierarchicalConfiguration cfg : telemetryConfig.configurationsAt(CONFIG)) {
114 DefaultTelemetryConfig config = loadTelemetryConfig(cfg);
115 configs.put(config.name(), config);
116 provider.addConfig(config);
117 }
118 configs.clear();
119 return provider;
120 }
121
122 /**
123 * Loads a telemetry configuration from the supplied hierarchical configuration.
124 *
125 * @param telemetryCfg hierarchical configuration containing the telemetry config definition
126 * @return telemetry configuration
127 */
128 public DefaultTelemetryConfig loadTelemetryConfig(HierarchicalConfiguration telemetryCfg) {
129 String name = telemetryCfg.getString(NAME);
130 String parentsString = telemetryCfg.getString(EXTENDS, "");
131 List<TelemetryConfig> parents = Lists.newArrayList();
132
133 if (!"".equals(parentsString)) {
134 List<String> parentsNames;
135 if (parentsString.contains(",")) {
136 parentsNames = Arrays.asList(
137 parentsString.replace(" ", "").split(","));
138 } else {
139 parentsNames = Lists.newArrayList(parentsString);
140 }
141 parents = parentsNames.stream().map(parent -> (parent != null) ?
142 configs.get(parent) : null).collect(Collectors.toList());
143 }
144
145 String typeStr = telemetryCfg.getString(TYPE, getParentAttribute(parents, TYPE));
146 String manufacturer = telemetryCfg.getString(MFG, getParentAttribute(parents, MFG));
147 String swVersion = telemetryCfg.getString(SW, getParentAttribute(parents, SW));
148
149 // note that we do not inherits enabled property from parent
150 String enabledStr = telemetryCfg.getString(ENABLED);
151
152 boolean enabled = enabledStr != null && enabledStr.equalsIgnoreCase(TRUE);
153
154 TelemetryConfig.ConfigType type = type(typeStr);
155
156 if (type == null) {
157 return null;
158 }
159
160 return new DefaultTelemetryConfig(name, type, parents, manufacturer,
161 swVersion, enabled, parseProperties(parents, telemetryCfg));
162 }
163
164 private TelemetryConfig.ConfigType type(String typeStr) {
165 switch (typeStr.toUpperCase()) {
166 case "GRPC" :
167 return GRPC;
168 case "KAFKA":
169 return KAFKA;
170 case "REST":
171 return REST;
172 case "INFLUXDB":
173 return INFLUXDB;
174 case "PROMETHEUS":
175 return PROMETHEUS;
176 case "UNKNOWN":
177 default:
178 return UNKNOWN;
179 }
180 }
181
182 // Returns the specified property from the highest priority parent
183 private String getParentAttribute(List<TelemetryConfig> parents, String attribute) {
184 if (!parents.isEmpty()) {
185 TelemetryConfig parent = parents.get(0);
186 switch (attribute) {
187 case TYPE:
188 return parent.type().name().toLowerCase();
189 case MFG:
190 return parent.manufacturer();
191 case SW:
192 return parent.swVersion();
193 default:
194 throw new IllegalArgumentException("Unsupported attribute");
195 }
196 }
197 return "";
198 }
199
200 // Parses the properties section.
201 private Map<String, String> parseProperties(List<TelemetryConfig> parents,
202 HierarchicalConfiguration config) {
203 ImmutableMap.Builder<String, String> properties = ImmutableMap.builder();
204
205 // note that, we only allow the inheritance from single source
206 Map<String, String> parentConfigs = Maps.newHashMap();
207 if (!parents.isEmpty()) {
208 TelemetryConfig parent = parents.get(0);
209 parentConfigs = parent.properties();
210 }
211
212 properties.putAll(parentConfigs);
213
214 for (HierarchicalConfiguration b : config.configurationsAt(PROPERTY)) {
215 properties.put(b.getString(NAME), (String) b.getRootNode().getValue());
216 }
217 return properties.build();
218 }
219}