blob: 7ae4cec9f3c6fa969756f25867f8bfec2f1a6179 [file] [log] [blame]
kdarapu97843dc2018-05-10 12:46:32 +05301/*
2 * Copyright 2017-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.nodemetrics.impl;
17
kdarapu97843dc2018-05-10 12:46:32 +053018import org.hyperic.sigar.CpuPerc;
19import org.hyperic.sigar.FileSystemUsage;
20import org.hyperic.sigar.Mem;
21import org.hyperic.sigar.Sigar;
22import org.hyperic.sigar.SigarException;
23import org.onlab.util.KryoNamespace;
24import org.onlab.util.Tools;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070025import org.onosproject.cfg.ComponentConfigService;
kdarapu97843dc2018-05-10 12:46:32 +053026import org.onosproject.cluster.ClusterService;
27import org.onosproject.cluster.NodeId;
28import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
nitinanand920fcb42018-05-18 17:30:36 +053030import org.onosproject.nodemetrics.NodeCpuUsage;
kdarapu97843dc2018-05-10 12:46:32 +053031import org.onosproject.nodemetrics.NodeDiskUsage;
nitinanand920fcb42018-05-18 17:30:36 +053032import org.onosproject.nodemetrics.NodeMemoryUsage;
kdarapu97843dc2018-05-10 12:46:32 +053033import org.onosproject.nodemetrics.NodeMetricsService;
34import org.onosproject.nodemetrics.Units;
35import org.onosproject.store.serializers.KryoNamespaces;
36import org.onosproject.store.service.EventuallyConsistentMap;
37import org.onosproject.store.service.LogicalClockService;
38import org.onosproject.store.service.StorageService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070039import org.osgi.service.component.ComponentContext;
40import org.osgi.service.component.annotations.Activate;
41import org.osgi.service.component.annotations.Component;
42import org.osgi.service.component.annotations.Deactivate;
43import org.osgi.service.component.annotations.Modified;
44import org.osgi.service.component.annotations.Reference;
45import org.osgi.service.component.annotations.ReferenceCardinality;
kdarapu97843dc2018-05-10 12:46:32 +053046import org.slf4j.Logger;
47import org.slf4j.LoggerFactory;
48
Ray Milkeyd84f89b2018-08-17 14:54:17 -070049import java.util.Dictionary;
kdarapu97843dc2018-05-10 12:46:32 +053050import java.util.Map;
nitinanand920fcb42018-05-18 17:30:36 +053051import java.util.Objects;
kdarapu97843dc2018-05-10 12:46:32 +053052import java.util.concurrent.Executors;
53import java.util.concurrent.ScheduledExecutorService;
54import java.util.concurrent.ScheduledFuture;
55import java.util.concurrent.TimeUnit;
56import java.util.stream.Collectors;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070057
nitinanand920fcb42018-05-18 17:30:36 +053058import static org.onlab.util.Tools.getIntegerProperty;
59
kdarapu97843dc2018-05-10 12:46:32 +053060
Ray Milkeyd84f89b2018-08-17 14:54:17 -070061@Component(immediate = true, service = NodeMetricsService.class)
kdarapu97843dc2018-05-10 12:46:32 +053062public class NodeMetricsManager implements NodeMetricsService {
63 private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 15;
64 private static final String SLASH = "/";
65 private static final Double PERCENTAGE_MULTIPLIER = 100.0;
66 private final Logger log = LoggerFactory
67 .getLogger(this.getClass());
68
Ray Milkeyd84f89b2018-08-17 14:54:17 -070069 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kdarapu97843dc2018-05-10 12:46:32 +053070 protected CoreService coreService;
71
Ray Milkeyd84f89b2018-08-17 14:54:17 -070072 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kdarapu97843dc2018-05-10 12:46:32 +053073 protected StorageService storageService;
74
Ray Milkeyd84f89b2018-08-17 14:54:17 -070075 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kdarapu97843dc2018-05-10 12:46:32 +053076 protected ClusterService clusterService;
77
Ray Milkeyd84f89b2018-08-17 14:54:17 -070078 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kdarapu97843dc2018-05-10 12:46:32 +053079 protected LogicalClockService clockService;
80
Ray Milkeyd84f89b2018-08-17 14:54:17 -070081 @Reference(cardinality = ReferenceCardinality.MANDATORY)
nitinanand920fcb42018-05-18 17:30:36 +053082 protected ComponentConfigService cfgService;
83
kdarapu97843dc2018-05-10 12:46:32 +053084 private ScheduledExecutorService metricsExecutor;
85 private ScheduledFuture<?> scheduledTask;
86
87 private ApplicationId appId;
88 private NodeId localNodeId;
89
nitinanand920fcb42018-05-18 17:30:36 +053090 private EventuallyConsistentMap<NodeId, NodeMemoryUsage> memoryStore;
kdarapu97843dc2018-05-10 12:46:32 +053091 private EventuallyConsistentMap<NodeId, NodeDiskUsage> diskStore;
nitinanand920fcb42018-05-18 17:30:36 +053092 private EventuallyConsistentMap<NodeId, NodeCpuUsage> cpuStore;
kdarapu97843dc2018-05-10 12:46:32 +053093
94 private Sigar sigar;
95
Ray Milkeyd84f89b2018-08-17 14:54:17 -070096 //@Property(name = "metricPollFrequencySeconds", intValue = DEFAULT_POLL_FREQUENCY_SECONDS,
97 // label = "Frequency (in seconds) for polling controller metrics")
nitinanand920fcb42018-05-18 17:30:36 +053098 protected int metricPollFrequencySeconds = DEFAULT_POLL_FREQUENCY_SECONDS;
99
kdarapu97843dc2018-05-10 12:46:32 +0530100 @Activate
nitinanand920fcb42018-05-18 17:30:36 +0530101 public void activate(ComponentContext context) {
kdarapu97843dc2018-05-10 12:46:32 +0530102 appId = coreService
103 .registerApplication("org.onosproject.nodemetrics");
nitinanand920fcb42018-05-18 17:30:36 +0530104 cfgService.registerProperties(getClass());
kdarapu97843dc2018-05-10 12:46:32 +0530105 metricsExecutor = Executors.newSingleThreadScheduledExecutor(
106 Tools.groupedThreads("nodemetrics/pollingStatics",
107 "statistics-executor-%d", log));
108
109 localNodeId = clusterService.getLocalNode().id();
110 KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
111 .register(KryoNamespaces.API)
nitinanand920fcb42018-05-18 17:30:36 +0530112 .register(NodeMemoryUsage.class)
kdarapu97843dc2018-05-10 12:46:32 +0530113 .register(NodeDiskUsage.class)
nitinanand920fcb42018-05-18 17:30:36 +0530114 .register(NodeCpuUsage.class)
kdarapu97843dc2018-05-10 12:46:32 +0530115 .register(Units.class);
nitinanand920fcb42018-05-18 17:30:36 +0530116 memoryStore = storageService.<NodeId, NodeMemoryUsage>eventuallyConsistentMapBuilder()
kdarapu97843dc2018-05-10 12:46:32 +0530117 .withSerializer(serializer)
118 .withTimestampProvider((nodeId, memory) -> clockService.getTimestamp())
119 .withName("nodemetrics-memory")
120 .build();
121
122 diskStore = storageService.<NodeId, NodeDiskUsage>eventuallyConsistentMapBuilder()
123 .withSerializer(serializer)
124 .withTimestampProvider((nodeId, disk) -> clockService.getTimestamp())
125 .withName("nodemetrics-disk")
126 .build();
127
nitinanand920fcb42018-05-18 17:30:36 +0530128 cpuStore = storageService.<NodeId, NodeCpuUsage>eventuallyConsistentMapBuilder()
kdarapu97843dc2018-05-10 12:46:32 +0530129 .withSerializer(serializer)
130 .withTimestampProvider((nodeId, cpu) -> clockService.getTimestamp())
131 .withName("nodemetrics-cpu")
132 .build();
nitinanand920fcb42018-05-18 17:30:36 +0530133 modified(context);
kdarapu97843dc2018-05-10 12:46:32 +0530134 sigar = new Sigar();
135 pollMetrics();
136 }
137
138 @Deactivate
139 public void deactivate() {
nitinanand920fcb42018-05-18 17:30:36 +0530140 cfgService.unregisterProperties(getClass(), false);
kdarapu97843dc2018-05-10 12:46:32 +0530141 scheduledTask.cancel(true);
142 metricsExecutor.shutdown();
143 sigar.close();
144 }
145
nitinanand920fcb42018-05-18 17:30:36 +0530146 @Modified
147 public void modified(ComponentContext context) {
148 if (context == null) {
149 log.info("No component configuration");
150 return;
151 }
152
153 Dictionary<?, ?> properties = context.getProperties();
154 int newPollFrequency = getNewPollFrequency(properties);
155 //First time call to this modified method is when app activates
156 if (Objects.isNull(scheduledTask)) {
157 metricPollFrequencySeconds = newPollFrequency;
158 scheduledTask = schedulePolling();
159 } else {
160 if (newPollFrequency != metricPollFrequencySeconds) {
161 metricPollFrequencySeconds = newPollFrequency;
162 //stops the old scheduled task
163 scheduledTask.cancel(true);
164 //schedules new task at the new polling rate
165 scheduledTask = schedulePolling();
166 }
167 }
168 }
169
kdarapu97843dc2018-05-10 12:46:32 +0530170 @Override
nitinanand920fcb42018-05-18 17:30:36 +0530171 public Map<NodeId, NodeMemoryUsage> memory() {
kdarapu97843dc2018-05-10 12:46:32 +0530172 return this.ecToMap(memoryStore);
173 }
174
175 @Override
176 public Map<NodeId, NodeDiskUsage> disk() {
177 return this.ecToMap(diskStore);
178 }
179
180 @Override
nitinanand920fcb42018-05-18 17:30:36 +0530181 public Map<NodeId, NodeCpuUsage> cpu() {
kdarapu97843dc2018-05-10 12:46:32 +0530182 return this.ecToMap(cpuStore);
183 }
184
185 @Override
nitinanand920fcb42018-05-18 17:30:36 +0530186 public NodeMemoryUsage memory(NodeId nodeid) {
kdarapu97843dc2018-05-10 12:46:32 +0530187 return memoryStore.get(nodeid);
188 }
189
190 @Override
191 public NodeDiskUsage disk(NodeId nodeid) {
192 return diskStore.get(nodeid);
193 }
194
195 @Override
nitinanand920fcb42018-05-18 17:30:36 +0530196 public NodeCpuUsage cpu(NodeId nodeid) {
kdarapu97843dc2018-05-10 12:46:32 +0530197 return cpuStore.get(nodeid);
198 }
199
200 private ScheduledFuture schedulePolling() {
201 return metricsExecutor.scheduleAtFixedRate(this::pollMetrics,
nitinanand920fcb42018-05-18 17:30:36 +0530202 metricPollFrequencySeconds / 4,
203 metricPollFrequencySeconds, TimeUnit.SECONDS);
204 }
205
206 private int getNewPollFrequency(Dictionary<?, ?> properties) {
207 int newPollFrequency;
208 try {
209 newPollFrequency = getIntegerProperty(properties, "metricPollFrequencySeconds");
210 //String s = getIntegerProperty(properties, "metricPollFrequencySeconds");
211 //newPollFrequency = isNullOrEmpty(s) ? pollFrequency : Integer.parseInt(s.trim());
212 } catch (NumberFormatException | ClassCastException e) {
213 newPollFrequency = DEFAULT_POLL_FREQUENCY_SECONDS;
214 }
215 return newPollFrequency;
kdarapu97843dc2018-05-10 12:46:32 +0530216 }
217
218 private <K, V> Map<K, V> ecToMap(EventuallyConsistentMap<K, V> ecMap) {
219 return ecMap.entrySet()
220 .stream()
221 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
222 }
nitinanand920fcb42018-05-18 17:30:36 +0530223
kdarapu97843dc2018-05-10 12:46:32 +0530224 private void pollMetrics() {
225 try {
226 CpuPerc cpu = sigar.getCpuPerc();
227 Mem mem = sigar.getMem();
228 FileSystemUsage disk = sigar.getFileSystemUsage(SLASH);
229
nitinanand920fcb42018-05-18 17:30:36 +0530230 NodeMemoryUsage memoryNode = new NodeMemoryUsage.Builder().free(mem.getFree())
kdarapu97843dc2018-05-10 12:46:32 +0530231 .used(mem.getUsed()).total(mem.getTotal()).withUnit(Units.BYTES)
232 .withNode(localNodeId).build();
nitinanand920fcb42018-05-18 17:30:36 +0530233 NodeCpuUsage cpuNode = new NodeCpuUsage.Builder().withNode(localNodeId)
kdarapu97843dc2018-05-10 12:46:32 +0530234 .usage(cpu.getCombined() * PERCENTAGE_MULTIPLIER).build();
235 NodeDiskUsage diskNode = new NodeDiskUsage.Builder().withNode(localNodeId)
236 .free(disk.getFree()).used(disk.getUsed()).withUnit(Units.KBYTES)
237 .total(disk.getTotal()).build();
238 diskStore.put(localNodeId, diskNode);
239 memoryStore.put(localNodeId, memoryNode);
240 cpuStore.put(localNodeId, cpuNode);
241
242 } catch (SigarException e) {
243 log.error("Exception occurred ", e);
244 }
245
246 }
247}