blob: 9f63b1d3872d253c481223ba05e428788ed45833 [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;
Jian Li667c6eb2019-01-07 23:01:12 +090046import static org.onosproject.openstacktelemetry.api.config.TelemetryConfig.Status.ENABLED;
Jian Li69600e02018-12-24 13:21:18 +090047import static org.onosproject.openstacktelemetry.config.DefaultPrometheusTelemetryConfig.fromTelemetryConfig;
48
boyoung21c5f5f42018-09-27 20:29:41 +090049/**
50 * Prometheus telemetry manager.
51 */
boyoung2a8549d22018-11-23 20:42:37 +090052@Component(immediate = true, service = PrometheusTelemetryAdminService.class)
boyoung21c5f5f42018-09-27 20:29:41 +090053public class PrometheusTelemetryManager implements PrometheusTelemetryAdminService {
54
55 private final Logger log = LoggerFactory.getLogger(getClass());
56
Jian Lia61e0b62018-12-28 19:10:10 +090057 private Map<String, Server> prometheusExporters = Maps.newConcurrentMap();
boyoung21c5f5f42018-09-27 20:29:41 +090058
boyoung2a8549d22018-11-23 20:42:37 +090059 private static final String FLOW_TYPE = "flowType";
60 private static final String DEVICE_ID = "deviceId";
61 private static final String INPUT_INTERFACE_ID = "inputInterfaceId";
62 private static final String OUTPUT_INTERFACE_ID = "outputInterfaceId";
63 private static final String VLAN_ID = "vlanId";
64 private static final String VXLAN_ID = "vxlanId";
65 private static final String SRC_IP = "srcIp";
66 private static final String DST_IP = "dstIp";
67 private static final String SRC_PORT = "srcPort";
68 private static final String DST_PORT = "dstPort";
69 private static final String PROTOCOL = "protocol";
boyoung21c5f5f42018-09-27 20:29:41 +090070
boyoung2a8549d22018-11-23 20:42:37 +090071 private static final String[] LABEL_TAGS = {
72 FLOW_TYPE, DEVICE_ID, INPUT_INTERFACE_ID, OUTPUT_INTERFACE_ID,
73 VLAN_ID, VXLAN_ID, SRC_IP, DST_IP, SRC_PORT, DST_PORT, PROTOCOL
74 };
boyoung21c5f5f42018-09-27 20:29:41 +090075
boyoung2a8549d22018-11-23 20:42:37 +090076 private static final String STAT_NAME_VM2VM_BYTE = "vm2vm_byte";
77 private static final String STAT_NAME_VM2VM_BYTE_PREV = "vm2vm_byte_prev";
78 private static final String STAT_NAME_VM2VM_BYTE_CURR = "vm2vm_byte_curr";
79 private static final String STAT_NAME_VM2VM_PKT = "vm2vm_pkt";
80 private static final String STAT_NAME_VM2VM_PKT_PREV = "vm2vm_pkt_prev";
81 private static final String STAT_NAME_VM2VM_PKT_CURR = "vm2vm_pkt_curr";
82 private static final String STAT_NAME_ERROR_PKT = "error_pkt";
83 private static final String STAT_NAME_DROP_PKT = "drop_pkt";
boyoung21c5f5f42018-09-27 20:29:41 +090084
boyoung2a8549d22018-11-23 20:42:37 +090085 private static final String HELP_MSG_VM2VM_BYTE =
86 "SONA flow bytes statistics for VM to VM";
87 private static final String HELP_MSG_VM2VM_BYTE_PREV =
88 HELP_MSG_VM2VM_BYTE + " [Accumulated previous byte]";
89 private static final String HELP_MSG_VM2VM_BYTE_CURR =
90 HELP_MSG_VM2VM_BYTE + " [Accumulated current byte]";
91 private static final String HELP_MSG_VM2VM_PKT =
92 "SONA flow packets statistics for VM to VM";
93 private static final String HELP_MSG_VM2VM_PKT_PREV =
94 HELP_MSG_VM2VM_PKT + " [Accumulated previous pkt]";
95 private static final String HELP_MSG_VM2VM_PKT_CURR =
96 HELP_MSG_VM2VM_PKT + " [Accumulated current pkt]";
97 private static final String HELP_MSG_ERROR = "SONA error statistics";
98 private static final String HELP_MSG_DROP = "SONA drop statistics";
boyoung21c5f5f42018-09-27 20:29:41 +090099
boyoung2a8549d22018-11-23 20:42:37 +0900100 private static Gauge byteVM2VM = Gauge.build()
101 .name(STAT_NAME_VM2VM_BYTE)
102 .help(HELP_MSG_VM2VM_BYTE)
103 .labelNames(LABEL_TAGS)
104 .register();
105 private static Gauge byteVM2VMPrev = Gauge.build()
106 .name(STAT_NAME_VM2VM_BYTE_PREV)
107 .help(HELP_MSG_VM2VM_BYTE_PREV)
108 .labelNames(LABEL_TAGS)
109 .register();
110 private static Gauge byteVM2VMCurr = Gauge.build()
111 .name(STAT_NAME_VM2VM_BYTE_CURR)
112 .help(HELP_MSG_VM2VM_BYTE_CURR)
113 .labelNames(LABEL_TAGS)
114 .register();
115 private static Gauge pktVM2VM = Gauge.build()
116 .name(STAT_NAME_VM2VM_PKT)
117 .help(HELP_MSG_VM2VM_PKT)
118 .labelNames(LABEL_TAGS)
119 .register();
120 private static Gauge pktVM2VMPrev = Gauge.build()
121 .name(STAT_NAME_VM2VM_PKT_PREV)
122 .help(HELP_MSG_VM2VM_PKT_PREV)
123 .labelNames(LABEL_TAGS)
124 .register();
125 private static Gauge pktVM2VMCurr = Gauge.build()
126 .name(STAT_NAME_VM2VM_PKT_CURR)
127 .help(HELP_MSG_VM2VM_PKT_CURR)
128 .labelNames(LABEL_TAGS)
129 .register();
130 private static Counter pktError = Counter.build()
131 .name(STAT_NAME_ERROR_PKT)
132 .help(HELP_MSG_ERROR)
133 .labelNames(LABEL_TAGS)
134 .register();
135 private static Counter pktDrop = Counter.build()
136 .name(STAT_NAME_DROP_PKT)
137 .help(HELP_MSG_DROP)
138 .labelNames(LABEL_TAGS)
139 .register();
boyoung21c5f5f42018-09-27 20:29:41 +0900140
Ray Milkeydf521292018-10-04 15:13:33 -0700141 @Reference(cardinality = ReferenceCardinality.MANDATORY)
boyoung21c5f5f42018-09-27 20:29:41 +0900142 protected OpenstackTelemetryService openstackTelemetryService;
143
Jian Li69600e02018-12-24 13:21:18 +0900144 @Reference(cardinality = ReferenceCardinality.MANDATORY)
145 protected TelemetryConfigService telemetryConfigService;
146
boyoung21c5f5f42018-09-27 20:29:41 +0900147 @Activate
148 protected void activate() {
149 openstackTelemetryService.addTelemetryService(this);
150 log.info("Started");
151 }
152
153 @Deactivate
154 protected void deactivate() {
Jian Lia61e0b62018-12-28 19:10:10 +0900155 stopAll();
boyoung21c5f5f42018-09-27 20:29:41 +0900156 openstackTelemetryService.removeTelemetryService(this);
157 log.info("Stopped");
158 }
159
160 @Override
Jian Lia61e0b62018-12-28 19:10:10 +0900161 public void startAll() {
boyoung21c5f5f42018-09-27 20:29:41 +0900162 log.info("Prometheus exporter starts.");
163
Jian Lia61e0b62018-12-28 19:10:10 +0900164 telemetryConfigService.getConfigsByType(PROMETHEUS).forEach(c -> start(c.name()));
boyoung21c5f5f42018-09-27 20:29:41 +0900165 }
166
167 @Override
Jian Lia61e0b62018-12-28 19:10:10 +0900168 public void stopAll() {
169 prometheusExporters.values().forEach(pe -> {
Jian Li69600e02018-12-24 13:21:18 +0900170 try {
171 pe.stop();
172 } catch (Exception e) {
173 log.warn("Failed to stop prometheus server due to {}", e);
174 }
175 });
boyoung21c5f5f42018-09-27 20:29:41 +0900176 log.info("Prometheus exporter has stopped");
177 }
178
179 @Override
Jian Lia61e0b62018-12-28 19:10:10 +0900180 public void restartAll() {
181 stopAll();
182 startAll();
boyoung21c5f5f42018-09-27 20:29:41 +0900183 }
184
185 @Override
186 public void publish(Set<FlowInfo> flowInfos) {
boyoung2a8549d22018-11-23 20:42:37 +0900187 if (flowInfos.isEmpty()) {
188 log.debug("No FlowInfo record to publish");
boyoung21c5f5f42018-09-27 20:29:41 +0900189 return;
190 }
191
192 long flowByte;
193 int flowPkt;
boyoung2a8549d22018-11-23 20:42:37 +0900194 String[] labelValues;
195
boyoung21c5f5f42018-09-27 20:29:41 +0900196 for (FlowInfo flowInfo: flowInfos) {
197 flowByte = flowInfo.statsInfo().currAccBytes() - flowInfo.statsInfo().prevAccBytes();
198 flowPkt = flowInfo.statsInfo().currAccPkts() - flowInfo.statsInfo().prevAccPkts();
boyoung2a8549d22018-11-23 20:42:37 +0900199 labelValues = getLabelValues(flowInfo);
200 byteVM2VM.labels(labelValues).set(flowByte);
201 byteVM2VMPrev.labels(labelValues).set(flowInfo.statsInfo().prevAccBytes());
202 byteVM2VMCurr.labels(labelValues).set(flowInfo.statsInfo().currAccBytes());
203 pktVM2VM.labels(labelValues).set(flowPkt);
204 pktVM2VMPrev.labels(labelValues).set(flowInfo.statsInfo().prevAccPkts());
205 pktVM2VMCurr.labels(labelValues).set(flowInfo.statsInfo().currAccPkts());
206 pktError.labels(labelValues).inc(flowInfo.statsInfo().errorPkts());
207 pktDrop.labels(labelValues).inc(flowInfo.statsInfo().dropPkts());
boyoung21c5f5f42018-09-27 20:29:41 +0900208 }
209 }
210
211 @Override
212 public boolean isRunning() {
Jian Li69600e02018-12-24 13:21:18 +0900213 return !prometheusExporters.isEmpty();
boyoung21c5f5f42018-09-27 20:29:41 +0900214 }
Jian Lia61e0b62018-12-28 19:10:10 +0900215
216 @Override
Jian Li667c6eb2019-01-07 23:01:12 +0900217 public boolean start(String name) {
218 boolean success = false;
Jian Lia61e0b62018-12-28 19:10:10 +0900219 TelemetryConfig config = telemetryConfigService.getConfig(name);
220 PrometheusTelemetryConfig prometheusConfig = fromTelemetryConfig(config);
221
Jian Li667c6eb2019-01-07 23:01:12 +0900222 if (prometheusConfig != null && !config.name().equals(PROMETHEUS_SCHEME) &&
223 config.status() == ENABLED) {
Jian Lia61e0b62018-12-28 19:10:10 +0900224 try {
225 // TODO Offer a 'Authentication'
226 Server prometheusExporter = new Server(prometheusConfig.port());
227 ServletContextHandler context = new ServletContextHandler();
228 context.setContextPath("/");
229 prometheusExporter.setHandler(context);
230 context.addServlet(new ServletHolder(new MetricsServlet()), "/metrics");
231
232 log.info("Prometheus server start");
233
234 prometheusExporter.start();
235
236 prometheusExporters.put(name, prometheusExporter);
237
Jian Li667c6eb2019-01-07 23:01:12 +0900238 success = true;
239
Jian Lia61e0b62018-12-28 19:10:10 +0900240 } catch (Exception ex) {
Jian Li667c6eb2019-01-07 23:01:12 +0900241 log.warn("Failed to start prometheus server due to {}", ex);
Jian Lia61e0b62018-12-28 19:10:10 +0900242 }
243 }
Jian Li667c6eb2019-01-07 23:01:12 +0900244
245 return success;
Jian Lia61e0b62018-12-28 19:10:10 +0900246 }
247
248 @Override
249 public void stop(String name) {
250 try {
251 Server pe = prometheusExporters.get(name);
252 if (pe != null) {
253 pe.stop();
254 prometheusExporters.remove(name);
255 }
256 } catch (Exception e) {
257 log.warn("Failed to stop prometheus server due to {}", e);
258 }
259 }
260
261 @Override
Jian Li667c6eb2019-01-07 23:01:12 +0900262 public boolean restart(String name) {
Jian Lia61e0b62018-12-28 19:10:10 +0900263 stop(name);
Jian Li667c6eb2019-01-07 23:01:12 +0900264 return start(name);
265 }
266
267 private String[] getLabelValues(FlowInfo flowInfo) {
268 String[] labelValues = new String[LABEL_TAGS.length];
269
270 labelValues[Arrays.asList(LABEL_TAGS).indexOf(FLOW_TYPE)]
271 = String.valueOf(flowInfo.flowType());
272 labelValues[Arrays.asList(LABEL_TAGS).indexOf(DEVICE_ID)]
273 = flowInfo.deviceId().toString();
274 labelValues[Arrays.asList(LABEL_TAGS).indexOf(INPUT_INTERFACE_ID)]
275 = String.valueOf(flowInfo.inputInterfaceId());
276 labelValues[Arrays.asList(LABEL_TAGS).indexOf(OUTPUT_INTERFACE_ID)]
277 = String.valueOf(flowInfo.outputInterfaceId());
278 labelValues[Arrays.asList(LABEL_TAGS).indexOf(VXLAN_ID)]
279 = String.valueOf(flowInfo.vxlanId());
280 labelValues[Arrays.asList(LABEL_TAGS).indexOf(SRC_IP)]
281 = flowInfo.srcIp().toString();
282 labelValues[Arrays.asList(LABEL_TAGS).indexOf(DST_IP)]
283 = flowInfo.dstIp().toString();
284 labelValues[Arrays.asList(LABEL_TAGS).indexOf(SRC_PORT)]
285 = getTpPort(flowInfo.srcPort());
286 labelValues[Arrays.asList(LABEL_TAGS).indexOf(DST_PORT)]
287 = getTpPort(flowInfo.dstPort());
288 labelValues[Arrays.asList(LABEL_TAGS).indexOf(PROTOCOL)]
289 = String.valueOf(flowInfo.protocol());
290 if (flowInfo.vlanId() != null) {
291 labelValues[Arrays.asList(LABEL_TAGS).indexOf(VLAN_ID)]
292 = flowInfo.vlanId().toString();
293 }
294 return labelValues;
295 }
296
297 private String getTpPort(TpPort tpPort) {
298 if (tpPort == null) {
299 return "";
300 }
301 return tpPort.toString();
Jian Lia61e0b62018-12-28 19:10:10 +0900302 }
boyoung21c5f5f42018-09-27 20:29:41 +0900303}