blob: 3e8c57b0c0ea41a3e139d3026e41189a0b7ff165 [file] [log] [blame]
Jian Lic132c112016-01-28 20:27:34 -08001/*
2 * Copyright 2016 Open Networking Laboratory
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.cpman.rest;
17
18import com.fasterxml.jackson.databind.JsonNode;
Jian Liba6b1172016-02-01 22:40:42 -080019import com.fasterxml.jackson.databind.node.ArrayNode;
Jian Lic132c112016-01-28 20:27:34 -080020import com.fasterxml.jackson.databind.node.ObjectNode;
Jian Li9f3a8852016-04-07 13:37:39 -070021import org.apache.commons.lang3.StringUtils;
Jian Lic132c112016-01-28 20:27:34 -080022import org.onosproject.cpman.ControlMetric;
23import org.onosproject.cpman.ControlMetricType;
Jian Lic132c112016-01-28 20:27:34 -080024import org.onosproject.cpman.ControlPlaneMonitorService;
Jian Li9f3a8852016-04-07 13:37:39 -070025import org.onosproject.cpman.ControlResource;
Jian Lic132c112016-01-28 20:27:34 -080026import org.onosproject.cpman.MetricValue;
Jian Li1a424692016-02-03 16:21:18 -080027import org.onosproject.cpman.SystemInfo;
28import org.onosproject.cpman.impl.DefaultSystemInfo;
29import org.onosproject.cpman.impl.SystemInfoFactory;
Jian Lic132c112016-01-28 20:27:34 -080030import org.onosproject.rest.AbstractWebResource;
Jian Li9f3a8852016-04-07 13:37:39 -070031import org.slf4j.Logger;
32import org.slf4j.LoggerFactory;
Jian Lic132c112016-01-28 20:27:34 -080033
34import javax.ws.rs.Consumes;
35import javax.ws.rs.POST;
36import javax.ws.rs.Path;
37import javax.ws.rs.Produces;
38import javax.ws.rs.core.MediaType;
39import javax.ws.rs.core.Response;
40import java.io.IOException;
41import java.io.InputStream;
Jian Li9f3a8852016-04-07 13:37:39 -070042import java.util.Iterator;
Jian Lic132c112016-01-28 20:27:34 -080043import java.util.Optional;
Jian Li9f3a8852016-04-07 13:37:39 -070044import java.util.Set;
45import java.util.stream.Collectors;
Jian Lic132c112016-01-28 20:27:34 -080046
Jian Liba6b1172016-02-01 22:40:42 -080047import static org.onlab.util.Tools.nullIsIllegal;
48
Jian Lic132c112016-01-28 20:27:34 -080049/**
Jian Li80c12702016-02-20 08:58:19 +090050 * Collect system metrics.
Jian Lic132c112016-01-28 20:27:34 -080051 */
Jian Li54df73e2016-02-01 17:09:03 -080052@Path("collector")
Jian Li80c12702016-02-20 08:58:19 +090053public class SystemMetricsCollectorWebResource extends AbstractWebResource {
Jian Lic132c112016-01-28 20:27:34 -080054
Jian Li9f3a8852016-04-07 13:37:39 -070055 private final Logger log = LoggerFactory.getLogger(getClass());
Jian Li80c12702016-02-20 08:58:19 +090056 private final ControlPlaneMonitorService service = get(ControlPlaneMonitorService.class);
57 private static final int UPDATE_INTERVAL_IN_MINUTE = 1;
58 private static final String INVALID_SYSTEM_SPECS = "Invalid system specifications";
59 private static final String INVALID_RESOURCE_NAME = "Invalid resource name";
60 private static final String INVALID_REQUEST = "Invalid request";
Jian Li9f3a8852016-04-07 13:37:39 -070061 private static final int PERCENT_CONSTANT = 100;
62
63 private static final Set<String> MEMORY_FIELD_SET = ControlResource.MEMORY_METRICS
64 .stream().map(type -> toCamelCase(type.toString(), true))
65 .collect(Collectors.toSet());
66
67 private static final Set<String> CPU_FIELD_SET = ControlResource.CPU_METRICS
68 .stream().map(type -> toCamelCase(type.toString(), true))
69 .collect(Collectors.toSet());
Jian Lic132c112016-01-28 20:27:34 -080070
71 /**
72 * Collects CPU metrics.
73 *
74 * @param stream JSON stream
75 * @return 200 OK
76 * @onos.rsModel CpuMetricsPost
77 */
78 @POST
Jian Li54df73e2016-02-01 17:09:03 -080079 @Path("cpu_metrics")
Jian Lic132c112016-01-28 20:27:34 -080080 @Consumes(MediaType.APPLICATION_JSON)
81 @Produces(MediaType.APPLICATION_JSON)
82 public Response cpuMetrics(InputStream stream) {
83 ObjectNode root = mapper().createObjectNode();
84 ControlMetric cm;
85 try {
86 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
Jian Li9f3a8852016-04-07 13:37:39 -070087
88 if (jsonTree == null || !checkFields(jsonTree, CPU_FIELD_SET)) {
89 ok(root).build();
90 }
91
92 long cpuLoad = nullIsIllegal((long) (jsonTree.get("cpuLoad").asDouble()
93 * PERCENT_CONSTANT), INVALID_REQUEST);
Jian Li1fdd2242016-02-05 10:01:19 -080094 long totalCpuTime = nullIsIllegal(jsonTree.get("totalCpuTime").asLong(), INVALID_REQUEST);
95 long sysCpuTime = nullIsIllegal(jsonTree.get("sysCpuTime").asLong(), INVALID_REQUEST);
96 long userCpuTime = nullIsIllegal(jsonTree.get("userCpuTime").asLong(), INVALID_REQUEST);
97 long cpuIdleTime = nullIsIllegal(jsonTree.get("cpuIdleTime").asLong(), INVALID_REQUEST);
Jian Lic132c112016-01-28 20:27:34 -080098
Jian Li1fdd2242016-02-05 10:01:19 -080099 cm = new ControlMetric(ControlMetricType.CPU_LOAD,
100 new MetricValue.Builder().load(cpuLoad).add());
101 service.updateMetric(cm, UPDATE_INTERVAL_IN_MINUTE, Optional.ofNullable(null));
Jian Lic132c112016-01-28 20:27:34 -0800102
Jian Li1fdd2242016-02-05 10:01:19 -0800103 cm = new ControlMetric(ControlMetricType.TOTAL_CPU_TIME,
104 new MetricValue.Builder().load(totalCpuTime).add());
105 service.updateMetric(cm, UPDATE_INTERVAL_IN_MINUTE, Optional.ofNullable(null));
Jian Lic132c112016-01-28 20:27:34 -0800106
Jian Li1fdd2242016-02-05 10:01:19 -0800107 cm = new ControlMetric(ControlMetricType.SYS_CPU_TIME,
108 new MetricValue.Builder().load(sysCpuTime).add());
109 service.updateMetric(cm, UPDATE_INTERVAL_IN_MINUTE, Optional.ofNullable(null));
Jian Lic132c112016-01-28 20:27:34 -0800110
Jian Li1fdd2242016-02-05 10:01:19 -0800111 cm = new ControlMetric(ControlMetricType.USER_CPU_TIME,
112 new MetricValue.Builder().load(userCpuTime).add());
113 service.updateMetric(cm, UPDATE_INTERVAL_IN_MINUTE, Optional.ofNullable(null));
Jian Lic132c112016-01-28 20:27:34 -0800114
Jian Li1fdd2242016-02-05 10:01:19 -0800115 cm = new ControlMetric(ControlMetricType.CPU_IDLE_TIME,
116 new MetricValue.Builder().load(cpuIdleTime).add());
117 service.updateMetric(cm, UPDATE_INTERVAL_IN_MINUTE, Optional.ofNullable(null));
Jian Lic132c112016-01-28 20:27:34 -0800118
119 } catch (IOException e) {
120 throw new IllegalArgumentException(e.getMessage());
Jian Li9f3a8852016-04-07 13:37:39 -0700121 } catch (IllegalArgumentException iae) {
122 log.error("[CPU] Illegal arguments in JSON input, msg: {}", iae.getMessage());
Jian Lic132c112016-01-28 20:27:34 -0800123 }
124 return ok(root).build();
125 }
126
127 /**
128 * Collects memory metrics.
129 *
130 * @param stream JSON stream
131 * @return 200 OK
132 * @onos.rsModel MemoryMetricsPost
133 */
134 @POST
Jian Li54df73e2016-02-01 17:09:03 -0800135 @Path("memory_metrics")
Jian Lic132c112016-01-28 20:27:34 -0800136 @Consumes(MediaType.APPLICATION_JSON)
137 @Produces(MediaType.APPLICATION_JSON)
138 public Response memoryMetrics(InputStream stream) {
139 ObjectNode root = mapper().createObjectNode();
140 ControlMetric cm;
141 try {
142 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
Jian Li9f3a8852016-04-07 13:37:39 -0700143
144 if (jsonTree == null || !checkFields(jsonTree, MEMORY_FIELD_SET)) {
145 ok(root).build();
146 }
147
Jian Li1fdd2242016-02-05 10:01:19 -0800148 long memUsed = nullIsIllegal(jsonTree.get("memoryUsed").asLong(), INVALID_REQUEST);
149 long memFree = nullIsIllegal(jsonTree.get("memoryFree").asLong(), INVALID_REQUEST);
Jian Li9f3a8852016-04-07 13:37:39 -0700150 long memTotal = memUsed + memFree;
151 long memUsedRatio = memTotal == 0L ? 0L : (memUsed * PERCENT_CONSTANT) / memTotal;
152 long memFreeRatio = memTotal == 0L ? 0L : (memFree * PERCENT_CONSTANT) / memTotal;
Jian Lic132c112016-01-28 20:27:34 -0800153
Jian Li1fdd2242016-02-05 10:01:19 -0800154 cm = new ControlMetric(ControlMetricType.MEMORY_USED_RATIO,
155 new MetricValue.Builder().load(memUsedRatio).add());
156 service.updateMetric(cm, UPDATE_INTERVAL_IN_MINUTE, Optional.ofNullable(null));
Jian Lic132c112016-01-28 20:27:34 -0800157
Jian Li1fdd2242016-02-05 10:01:19 -0800158 cm = new ControlMetric(ControlMetricType.MEMORY_FREE_RATIO,
159 new MetricValue.Builder().load(memFreeRatio).add());
160 service.updateMetric(cm, UPDATE_INTERVAL_IN_MINUTE, Optional.ofNullable(null));
Jian Lic132c112016-01-28 20:27:34 -0800161
Jian Li1fdd2242016-02-05 10:01:19 -0800162 cm = new ControlMetric(ControlMetricType.MEMORY_USED,
163 new MetricValue.Builder().load(memUsed).add());
164 service.updateMetric(cm, UPDATE_INTERVAL_IN_MINUTE, Optional.ofNullable(null));
Jian Lic132c112016-01-28 20:27:34 -0800165
Jian Li1fdd2242016-02-05 10:01:19 -0800166 cm = new ControlMetric(ControlMetricType.MEMORY_FREE,
167 new MetricValue.Builder().load(memFree).add());
168 service.updateMetric(cm, UPDATE_INTERVAL_IN_MINUTE, Optional.ofNullable(null));
Jian Lic132c112016-01-28 20:27:34 -0800169
170 } catch (IOException e) {
171 throw new IllegalArgumentException(e.getMessage());
Jian Li9f3a8852016-04-07 13:37:39 -0700172 } catch (IllegalArgumentException iae) {
173 log.error("[RAM] Illegal arguments in JSON input, msg: {}", iae.getMessage());
Jian Lic132c112016-01-28 20:27:34 -0800174 }
175 return ok(root).build();
176 }
177
178 /**
179 * Collects disk metrics.
180 *
181 * @param stream JSON stream
182 * @return 200 OK
183 * @onos.rsModel DiskMetricsPost
184 */
185 @POST
Jian Li54df73e2016-02-01 17:09:03 -0800186 @Path("disk_metrics")
Jian Lic132c112016-01-28 20:27:34 -0800187 @Consumes(MediaType.APPLICATION_JSON)
188 @Produces(MediaType.APPLICATION_JSON)
189 public Response diskMetrics(InputStream stream) {
190 ObjectNode root = mapper().createObjectNode();
Jian Li1fdd2242016-02-05 10:01:19 -0800191 ControlMetric cm;
Jian Lic132c112016-01-28 20:27:34 -0800192 try {
193 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
Jian Li9f3a8852016-04-07 13:37:39 -0700194 ArrayNode diskRes =
195 jsonTree.get("disks") == null ? mapper().createArrayNode() : (ArrayNode) jsonTree.get("disks");
196
Jian Li1fdd2242016-02-05 10:01:19 -0800197 for (JsonNode node : diskRes) {
Jian Liba6b1172016-02-01 22:40:42 -0800198 JsonNode resourceName = node.get("resourceName");
199 nullIsIllegal(resourceName, INVALID_RESOURCE_NAME);
Jian Lic132c112016-01-28 20:27:34 -0800200
Jian Li1fdd2242016-02-05 10:01:19 -0800201 long readBytes = nullIsIllegal(node.get("readBytes").asLong(), INVALID_REQUEST);
202 long writeBytes = nullIsIllegal(node.get("writeBytes").asLong(), INVALID_REQUEST);
Jian Lic132c112016-01-28 20:27:34 -0800203
Jian Li1fdd2242016-02-05 10:01:19 -0800204 cm = new ControlMetric(ControlMetricType.DISK_READ_BYTES,
205 new MetricValue.Builder().load(readBytes).add());
206 service.updateMetric(cm, UPDATE_INTERVAL_IN_MINUTE, resourceName.asText());
Jian Lic132c112016-01-28 20:27:34 -0800207
Jian Li1fdd2242016-02-05 10:01:19 -0800208 cm = new ControlMetric(ControlMetricType.DISK_WRITE_BYTES,
209 new MetricValue.Builder().load(writeBytes).add());
210 service.updateMetric(cm, UPDATE_INTERVAL_IN_MINUTE, resourceName.asText());
211 }
Jian Lic132c112016-01-28 20:27:34 -0800212 } catch (IOException e) {
213 throw new IllegalArgumentException(e.getMessage());
Jian Li9f3a8852016-04-07 13:37:39 -0700214 } catch (IllegalArgumentException iae) {
215 log.error("[DISK] Illegal arguments in JSON input, msg: {}", iae.getMessage());
Jian Lic132c112016-01-28 20:27:34 -0800216 }
217 return ok(root).build();
218 }
219
220 /**
221 * Collects network metrics.
222 *
223 * @param stream JSON stream
224 * @return 200 OK
225 * @onos.rsModel NetworkMetricsPost
226 */
227 @POST
Jian Li54df73e2016-02-01 17:09:03 -0800228 @Path("network_metrics")
Jian Lic132c112016-01-28 20:27:34 -0800229 @Consumes(MediaType.APPLICATION_JSON)
230 @Produces(MediaType.APPLICATION_JSON)
231 public Response networkMetrics(InputStream stream) {
232 ObjectNode root = mapper().createObjectNode();
Jian Li1fdd2242016-02-05 10:01:19 -0800233 ControlMetric cm;
Jian Lic132c112016-01-28 20:27:34 -0800234 try {
235 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
Jian Li9f3a8852016-04-07 13:37:39 -0700236
237 ArrayNode networkRes = jsonTree.get("networks") == null
238 ? mapper().createArrayNode() : (ArrayNode) jsonTree.get("networks");
239
Jian Li1fdd2242016-02-05 10:01:19 -0800240 for (JsonNode node : networkRes) {
Jian Liba6b1172016-02-01 22:40:42 -0800241 JsonNode resourceName = node.get("resourceName");
242 nullIsIllegal(resourceName, INVALID_RESOURCE_NAME);
Jian Lic132c112016-01-28 20:27:34 -0800243
Jian Li1fdd2242016-02-05 10:01:19 -0800244 long inBytes = nullIsIllegal(node.get("incomingBytes").asLong(), INVALID_REQUEST);
245 long outBytes = nullIsIllegal(node.get("outgoingBytes").asLong(), INVALID_REQUEST);
246 long inPackets = nullIsIllegal(node.get("incomingPackets").asLong(), INVALID_REQUEST);
247 long outPackets = nullIsIllegal(node.get("outgoingPackets").asLong(), INVALID_REQUEST);
Jian Lic132c112016-01-28 20:27:34 -0800248
Jian Li1fdd2242016-02-05 10:01:19 -0800249 cm = new ControlMetric(ControlMetricType.NW_INCOMING_BYTES,
250 new MetricValue.Builder().load(inBytes).add());
251 service.updateMetric(cm, UPDATE_INTERVAL_IN_MINUTE, resourceName.asText());
Jian Lic132c112016-01-28 20:27:34 -0800252
Jian Li1fdd2242016-02-05 10:01:19 -0800253 cm = new ControlMetric(ControlMetricType.NW_OUTGOING_BYTES,
254 new MetricValue.Builder().load(outBytes).add());
255 service.updateMetric(cm, UPDATE_INTERVAL_IN_MINUTE, resourceName.asText());
Jian Lic132c112016-01-28 20:27:34 -0800256
Jian Li1fdd2242016-02-05 10:01:19 -0800257 cm = new ControlMetric(ControlMetricType.NW_INCOMING_PACKETS,
258 new MetricValue.Builder().load(inPackets).add());
259 service.updateMetric(cm, UPDATE_INTERVAL_IN_MINUTE, resourceName.asText());
Jian Lic132c112016-01-28 20:27:34 -0800260
Jian Li1fdd2242016-02-05 10:01:19 -0800261 cm = new ControlMetric(ControlMetricType.NW_OUTGOING_PACKETS,
262 new MetricValue.Builder().load(outPackets).add());
263 service.updateMetric(cm, UPDATE_INTERVAL_IN_MINUTE, resourceName.asText());
264 }
Jian Lic132c112016-01-28 20:27:34 -0800265 } catch (IOException e) {
266 throw new IllegalArgumentException(e.getMessage());
267 }
268 return ok(root).build();
269 }
270
Jian Lic132c112016-01-28 20:27:34 -0800271 /**
Jian Li1a424692016-02-03 16:21:18 -0800272 * Collects system information.
273 * The system information includes the various control metrics
Jian Lic132c112016-01-28 20:27:34 -0800274 * which do not require aggregation.
275 *
276 * @param stream JSON stream
277 * @return 200 OK
Jian Li1a424692016-02-03 16:21:18 -0800278 * @onos.rsModel SystemInfoPost
Jian Lic132c112016-01-28 20:27:34 -0800279 */
280 @POST
Jian Li1a424692016-02-03 16:21:18 -0800281 @Path("system_info")
Jian Lic132c112016-01-28 20:27:34 -0800282 @Consumes(MediaType.APPLICATION_JSON)
283 @Produces(MediaType.APPLICATION_JSON)
Jian Li1a424692016-02-03 16:21:18 -0800284 public Response systemInfo(InputStream stream) {
Jian Lic132c112016-01-28 20:27:34 -0800285 ObjectNode root = mapper().createObjectNode();
286
287 try {
288 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
289 JsonNode numOfCores = jsonTree.get("numOfCores");
290 JsonNode numOfCpus = jsonTree.get("numOfCpus");
291 JsonNode cpuSpeed = jsonTree.get("cpuSpeed");
292 JsonNode totalMemory = jsonTree.get("totalMemory");
293
Jian Li1a424692016-02-03 16:21:18 -0800294 if (numOfCores != null && numOfCpus != null &&
295 cpuSpeed != null && totalMemory != null) {
296 SystemInfo systemInfo = new DefaultSystemInfo.Builder()
297 .numOfCores(numOfCores.asInt())
Jian Lic132c112016-01-28 20:27:34 -0800298 .numOfCpus(numOfCpus.asInt())
299 .cpuSpeed(cpuSpeed.asInt())
Jian Li1a424692016-02-03 16:21:18 -0800300 .totalMemory(totalMemory.asInt())
Jian Lic132c112016-01-28 20:27:34 -0800301 .build();
Jian Lic132c112016-01-28 20:27:34 -0800302
Jian Li1a424692016-02-03 16:21:18 -0800303 // try to store the system info.
304 SystemInfoFactory.getInstance().setSystemInfo(systemInfo);
Jian Lic132c112016-01-28 20:27:34 -0800305 } else {
306 throw new IllegalArgumentException(INVALID_SYSTEM_SPECS);
307 }
308
309 } catch (IOException e) {
310 throw new IllegalArgumentException(e.getMessage());
311 }
312 return ok(root).build();
313 }
Jian Li9f3a8852016-04-07 13:37:39 -0700314
315 private boolean checkFields(ObjectNode node, Set<String> original) {
316 Iterator<String> fieldNames = node.fieldNames();
317 while (fieldNames.hasNext()) {
318 String fieldName = fieldNames.next();
319 if (!original.contains(fieldName) || node.get(fieldName) == null) {
320 log.warn("Illegal field name: {}", fieldName);
321 return false;
322 }
323 }
324 return true;
325 }
326
327 private static String toCamelCase(String value, boolean startWithLowerCase) {
328 String[] strings = StringUtils.split(value.toLowerCase(), "_");
329 for (int i = startWithLowerCase ? 1 : 0; i < strings.length; i++) {
330 strings[i] = StringUtils.capitalize(strings[i]);
331 }
332 return StringUtils.join(strings);
333 }
Jian Li9d616492016-03-09 10:52:49 -0800334}