blob: 3ccc02ea1f28be889e36d6140916b3cfd0dc8fb9 [file] [log] [blame]
boyoung21c5f5f42018-09-27 20:29:41 +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
Jian Lia61e0b62018-12-28 19:10:10 +090018import com.google.common.collect.Maps;
Jian Li69600e02018-12-24 13:21:18 +090019import io.prometheus.client.Counter;
boyoung2a8549d22018-11-23 20:42:37 +090020import io.prometheus.client.Gauge;
Jian Li69600e02018-12-24 13:21:18 +090021import io.prometheus.client.exporter.MetricsServlet;
22import org.eclipse.jetty.server.Server;
23import org.eclipse.jetty.servlet.ServletContextHandler;
24import org.eclipse.jetty.servlet.ServletHolder;
boyoung2a8549d22018-11-23 20:42:37 +090025import org.onlab.packet.TpPort;
boyoung21c5f5f42018-09-27 20:29:41 +090026import org.onosproject.openstacktelemetry.api.FlowInfo;
27import org.onosproject.openstacktelemetry.api.OpenstackTelemetryService;
28import org.onosproject.openstacktelemetry.api.PrometheusTelemetryAdminService;
Jian Li69600e02018-12-24 13:21:18 +090029import org.onosproject.openstacktelemetry.api.TelemetryConfigService;
boyoung21c5f5f42018-09-27 20:29:41 +090030import org.onosproject.openstacktelemetry.api.config.PrometheusTelemetryConfig;
Jian Lia61e0b62018-12-28 19:10:10 +090031import org.onosproject.openstacktelemetry.api.config.TelemetryConfig;
Ray Milkeydf521292018-10-04 15:13:33 -070032import org.osgi.service.component.annotations.Activate;
33import org.osgi.service.component.annotations.Component;
34import org.osgi.service.component.annotations.Deactivate;
35import org.osgi.service.component.annotations.Reference;
36import org.osgi.service.component.annotations.ReferenceCardinality;
boyoung21c5f5f42018-09-27 20:29:41 +090037import org.slf4j.Logger;
38import org.slf4j.LoggerFactory;
39
boyoung2a8549d22018-11-23 20:42:37 +090040import java.util.Arrays;
Jian Lia61e0b62018-12-28 19:10:10 +090041import java.util.Map;
boyoung21c5f5f42018-09-27 20:29:41 +090042import java.util.Set;
43
Jian Li69600e02018-12-24 13:21:18 +090044import static org.onosproject.openstacktelemetry.api.Constants.PROMETHEUS_SCHEME;
45import static org.onosproject.openstacktelemetry.api.config.TelemetryConfig.ConfigType.PROMETHEUS;
46import static org.onosproject.openstacktelemetry.config.DefaultPrometheusTelemetryConfig.fromTelemetryConfig;
47
boyoung21c5f5f42018-09-27 20:29:41 +090048/**
49 * Prometheus telemetry manager.
50 */
boyoung2a8549d22018-11-23 20:42:37 +090051@Component(immediate = true, service = PrometheusTelemetryAdminService.class)
boyoung21c5f5f42018-09-27 20:29:41 +090052public class PrometheusTelemetryManager implements PrometheusTelemetryAdminService {
53
54 private final Logger log = LoggerFactory.getLogger(getClass());
55
Jian Lia61e0b62018-12-28 19:10:10 +090056 private Map<String, Server> prometheusExporters = Maps.newConcurrentMap();
boyoung21c5f5f42018-09-27 20:29:41 +090057
boyoung2a8549d22018-11-23 20:42:37 +090058 private static final String FLOW_TYPE = "flowType";
59 private static final String DEVICE_ID = "deviceId";
60 private static final String INPUT_INTERFACE_ID = "inputInterfaceId";
61 private static final String OUTPUT_INTERFACE_ID = "outputInterfaceId";
62 private static final String VLAN_ID = "vlanId";
63 private static final String VXLAN_ID = "vxlanId";
64 private static final String SRC_IP = "srcIp";
65 private static final String DST_IP = "dstIp";
66 private static final String SRC_PORT = "srcPort";
67 private static final String DST_PORT = "dstPort";
68 private static final String PROTOCOL = "protocol";
boyoung21c5f5f42018-09-27 20:29:41 +090069
boyoung2a8549d22018-11-23 20:42:37 +090070 private static final String[] LABEL_TAGS = {
71 FLOW_TYPE, DEVICE_ID, INPUT_INTERFACE_ID, OUTPUT_INTERFACE_ID,
72 VLAN_ID, VXLAN_ID, SRC_IP, DST_IP, SRC_PORT, DST_PORT, PROTOCOL
73 };
boyoung21c5f5f42018-09-27 20:29:41 +090074
boyoung2a8549d22018-11-23 20:42:37 +090075 private static final String STAT_NAME_VM2VM_BYTE = "vm2vm_byte";
76 private static final String STAT_NAME_VM2VM_BYTE_PREV = "vm2vm_byte_prev";
77 private static final String STAT_NAME_VM2VM_BYTE_CURR = "vm2vm_byte_curr";
78 private static final String STAT_NAME_VM2VM_PKT = "vm2vm_pkt";
79 private static final String STAT_NAME_VM2VM_PKT_PREV = "vm2vm_pkt_prev";
80 private static final String STAT_NAME_VM2VM_PKT_CURR = "vm2vm_pkt_curr";
81 private static final String STAT_NAME_ERROR_PKT = "error_pkt";
82 private static final String STAT_NAME_DROP_PKT = "drop_pkt";
boyoung21c5f5f42018-09-27 20:29:41 +090083
boyoung2a8549d22018-11-23 20:42:37 +090084 private static final String HELP_MSG_VM2VM_BYTE =
85 "SONA flow bytes statistics for VM to VM";
86 private static final String HELP_MSG_VM2VM_BYTE_PREV =
87 HELP_MSG_VM2VM_BYTE + " [Accumulated previous byte]";
88 private static final String HELP_MSG_VM2VM_BYTE_CURR =
89 HELP_MSG_VM2VM_BYTE + " [Accumulated current byte]";
90 private static final String HELP_MSG_VM2VM_PKT =
91 "SONA flow packets statistics for VM to VM";
92 private static final String HELP_MSG_VM2VM_PKT_PREV =
93 HELP_MSG_VM2VM_PKT + " [Accumulated previous pkt]";
94 private static final String HELP_MSG_VM2VM_PKT_CURR =
95 HELP_MSG_VM2VM_PKT + " [Accumulated current pkt]";
96 private static final String HELP_MSG_ERROR = "SONA error statistics";
97 private static final String HELP_MSG_DROP = "SONA drop statistics";
boyoung21c5f5f42018-09-27 20:29:41 +090098
boyoung2a8549d22018-11-23 20:42:37 +090099 private static Gauge byteVM2VM = Gauge.build()
100 .name(STAT_NAME_VM2VM_BYTE)
101 .help(HELP_MSG_VM2VM_BYTE)
102 .labelNames(LABEL_TAGS)
103 .register();
104 private static Gauge byteVM2VMPrev = Gauge.build()
105 .name(STAT_NAME_VM2VM_BYTE_PREV)
106 .help(HELP_MSG_VM2VM_BYTE_PREV)
107 .labelNames(LABEL_TAGS)
108 .register();
109 private static Gauge byteVM2VMCurr = Gauge.build()
110 .name(STAT_NAME_VM2VM_BYTE_CURR)
111 .help(HELP_MSG_VM2VM_BYTE_CURR)
112 .labelNames(LABEL_TAGS)
113 .register();
114 private static Gauge pktVM2VM = Gauge.build()
115 .name(STAT_NAME_VM2VM_PKT)
116 .help(HELP_MSG_VM2VM_PKT)
117 .labelNames(LABEL_TAGS)
118 .register();
119 private static Gauge pktVM2VMPrev = Gauge.build()
120 .name(STAT_NAME_VM2VM_PKT_PREV)
121 .help(HELP_MSG_VM2VM_PKT_PREV)
122 .labelNames(LABEL_TAGS)
123 .register();
124 private static Gauge pktVM2VMCurr = Gauge.build()
125 .name(STAT_NAME_VM2VM_PKT_CURR)
126 .help(HELP_MSG_VM2VM_PKT_CURR)
127 .labelNames(LABEL_TAGS)
128 .register();
129 private static Counter pktError = Counter.build()
130 .name(STAT_NAME_ERROR_PKT)
131 .help(HELP_MSG_ERROR)
132 .labelNames(LABEL_TAGS)
133 .register();
134 private static Counter pktDrop = Counter.build()
135 .name(STAT_NAME_DROP_PKT)
136 .help(HELP_MSG_DROP)
137 .labelNames(LABEL_TAGS)
138 .register();
boyoung21c5f5f42018-09-27 20:29:41 +0900139
Ray Milkeydf521292018-10-04 15:13:33 -0700140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
boyoung21c5f5f42018-09-27 20:29:41 +0900141 protected OpenstackTelemetryService openstackTelemetryService;
142
Jian Li69600e02018-12-24 13:21:18 +0900143 @Reference(cardinality = ReferenceCardinality.MANDATORY)
144 protected TelemetryConfigService telemetryConfigService;
145
boyoung21c5f5f42018-09-27 20:29:41 +0900146 @Activate
147 protected void activate() {
148 openstackTelemetryService.addTelemetryService(this);
149 log.info("Started");
150 }
151
152 @Deactivate
153 protected void deactivate() {
Jian Lia61e0b62018-12-28 19:10:10 +0900154 stopAll();
boyoung21c5f5f42018-09-27 20:29:41 +0900155 openstackTelemetryService.removeTelemetryService(this);
156 log.info("Stopped");
157 }
158
159 @Override
Jian Lia61e0b62018-12-28 19:10:10 +0900160 public void startAll() {
boyoung21c5f5f42018-09-27 20:29:41 +0900161 log.info("Prometheus exporter starts.");
162
Jian Lia61e0b62018-12-28 19:10:10 +0900163 telemetryConfigService.getConfigsByType(PROMETHEUS).forEach(c -> start(c.name()));
boyoung21c5f5f42018-09-27 20:29:41 +0900164 }
165
166 @Override
Jian Lia61e0b62018-12-28 19:10:10 +0900167 public void stopAll() {
168 prometheusExporters.values().forEach(pe -> {
Jian Li69600e02018-12-24 13:21:18 +0900169 try {
170 pe.stop();
171 } catch (Exception e) {
172 log.warn("Failed to stop prometheus server due to {}", e);
173 }
174 });
boyoung21c5f5f42018-09-27 20:29:41 +0900175 log.info("Prometheus exporter has stopped");
176 }
177
178 @Override
Jian Lia61e0b62018-12-28 19:10:10 +0900179 public void restartAll() {
180 stopAll();
181 startAll();
boyoung21c5f5f42018-09-27 20:29:41 +0900182 }
183
184 @Override
185 public void publish(Set<FlowInfo> flowInfos) {
boyoung2a8549d22018-11-23 20:42:37 +0900186 if (flowInfos.isEmpty()) {
187 log.debug("No FlowInfo record to publish");
boyoung21c5f5f42018-09-27 20:29:41 +0900188 return;
189 }
190
191 long flowByte;
192 int flowPkt;
boyoung2a8549d22018-11-23 20:42:37 +0900193 String[] labelValues;
194
boyoung21c5f5f42018-09-27 20:29:41 +0900195 for (FlowInfo flowInfo: flowInfos) {
196 flowByte = flowInfo.statsInfo().currAccBytes() - flowInfo.statsInfo().prevAccBytes();
197 flowPkt = flowInfo.statsInfo().currAccPkts() - flowInfo.statsInfo().prevAccPkts();
boyoung2a8549d22018-11-23 20:42:37 +0900198 labelValues = getLabelValues(flowInfo);
199 byteVM2VM.labels(labelValues).set(flowByte);
200 byteVM2VMPrev.labels(labelValues).set(flowInfo.statsInfo().prevAccBytes());
201 byteVM2VMCurr.labels(labelValues).set(flowInfo.statsInfo().currAccBytes());
202 pktVM2VM.labels(labelValues).set(flowPkt);
203 pktVM2VMPrev.labels(labelValues).set(flowInfo.statsInfo().prevAccPkts());
204 pktVM2VMCurr.labels(labelValues).set(flowInfo.statsInfo().currAccPkts());
205 pktError.labels(labelValues).inc(flowInfo.statsInfo().errorPkts());
206 pktDrop.labels(labelValues).inc(flowInfo.statsInfo().dropPkts());
boyoung21c5f5f42018-09-27 20:29:41 +0900207 }
208 }
209
boyoung2a8549d22018-11-23 20:42:37 +0900210 private String[] getLabelValues(FlowInfo flowInfo) {
211 String[] labelValues = new String[LABEL_TAGS.length];
212
213 labelValues[Arrays.asList(LABEL_TAGS).indexOf(FLOW_TYPE)]
214 = String.valueOf(flowInfo.flowType());
215 labelValues[Arrays.asList(LABEL_TAGS).indexOf(DEVICE_ID)]
216 = flowInfo.deviceId().toString();
217 labelValues[Arrays.asList(LABEL_TAGS).indexOf(INPUT_INTERFACE_ID)]
218 = String.valueOf(flowInfo.inputInterfaceId());
219 labelValues[Arrays.asList(LABEL_TAGS).indexOf(OUTPUT_INTERFACE_ID)]
220 = String.valueOf(flowInfo.outputInterfaceId());
221 labelValues[Arrays.asList(LABEL_TAGS).indexOf(VXLAN_ID)]
222 = String.valueOf(flowInfo.vxlanId());
223 labelValues[Arrays.asList(LABEL_TAGS).indexOf(SRC_IP)]
224 = flowInfo.srcIp().toString();
225 labelValues[Arrays.asList(LABEL_TAGS).indexOf(DST_IP)]
226 = flowInfo.dstIp().toString();
227 labelValues[Arrays.asList(LABEL_TAGS).indexOf(SRC_PORT)]
228 = getTpPort(flowInfo.srcPort());
229 labelValues[Arrays.asList(LABEL_TAGS).indexOf(DST_PORT)]
230 = getTpPort(flowInfo.dstPort());
231 labelValues[Arrays.asList(LABEL_TAGS).indexOf(PROTOCOL)]
232 = String.valueOf(flowInfo.protocol());
233 if (flowInfo.vlanId() != null) {
234 labelValues[Arrays.asList(LABEL_TAGS).indexOf(VLAN_ID)]
235 = flowInfo.vlanId().toString();
236 }
237 return labelValues;
238 }
239
240 private String getTpPort(TpPort tpPort) {
241 if (tpPort == null) {
242 return "";
243 }
244 return tpPort.toString();
245 }
246
boyoung21c5f5f42018-09-27 20:29:41 +0900247 @Override
248 public boolean isRunning() {
Jian Li69600e02018-12-24 13:21:18 +0900249 return !prometheusExporters.isEmpty();
boyoung21c5f5f42018-09-27 20:29:41 +0900250 }
Jian Lia61e0b62018-12-28 19:10:10 +0900251
252 @Override
253 public void start(String name) {
254 TelemetryConfig config = telemetryConfigService.getConfig(name);
255 PrometheusTelemetryConfig prometheusConfig = fromTelemetryConfig(config);
256
257 if (prometheusConfig != null &&
258 !config.name().equals(PROMETHEUS_SCHEME) && config.enabled()) {
259 try {
260 // TODO Offer a 'Authentication'
261 Server prometheusExporter = new Server(prometheusConfig.port());
262 ServletContextHandler context = new ServletContextHandler();
263 context.setContextPath("/");
264 prometheusExporter.setHandler(context);
265 context.addServlet(new ServletHolder(new MetricsServlet()), "/metrics");
266
267 log.info("Prometheus server start");
268
269 prometheusExporter.start();
270
271 prometheusExporters.put(name, prometheusExporter);
272
273 } catch (Exception ex) {
274 log.warn("Exception: {}", ex);
275 }
276 }
277 }
278
279 @Override
280 public void stop(String name) {
281 try {
282 Server pe = prometheusExporters.get(name);
283 if (pe != null) {
284 pe.stop();
285 prometheusExporters.remove(name);
286 }
287 } catch (Exception e) {
288 log.warn("Failed to stop prometheus server due to {}", e);
289 }
290 }
291
292 @Override
293 public void restart(String name) {
294 stop(name);
295 start(name);
296 }
boyoung21c5f5f42018-09-27 20:29:41 +0900297}