blob: 812ebb77b3b071bd6c43a6507ab62be31cfb50e1 [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
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
nitinanand920fcb42018-05-18 17:30:36 +053021import org.apache.felix.scr.annotations.Modified;
22import org.apache.felix.scr.annotations.Property;
kdarapu97843dc2018-05-10 12:46:32 +053023import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
nitinanand920fcb42018-05-18 17:30:36 +053026import org.osgi.service.component.ComponentContext;
27import org.onosproject.cfg.ComponentConfigService;
kdarapu97843dc2018-05-10 12:46:32 +053028import org.hyperic.sigar.CpuPerc;
29import org.hyperic.sigar.FileSystemUsage;
30import org.hyperic.sigar.Mem;
31import org.hyperic.sigar.Sigar;
32import org.hyperic.sigar.SigarException;
33import org.onlab.util.KryoNamespace;
34import org.onlab.util.Tools;
35import org.onosproject.cluster.ClusterService;
36import org.onosproject.cluster.NodeId;
37import org.onosproject.core.ApplicationId;
38import org.onosproject.core.CoreService;
nitinanand920fcb42018-05-18 17:30:36 +053039import org.onosproject.nodemetrics.NodeCpuUsage;
kdarapu97843dc2018-05-10 12:46:32 +053040import org.onosproject.nodemetrics.NodeDiskUsage;
nitinanand920fcb42018-05-18 17:30:36 +053041import org.onosproject.nodemetrics.NodeMemoryUsage;
kdarapu97843dc2018-05-10 12:46:32 +053042import org.onosproject.nodemetrics.NodeMetricsService;
43import org.onosproject.nodemetrics.Units;
44import org.onosproject.store.serializers.KryoNamespaces;
45import org.onosproject.store.service.EventuallyConsistentMap;
46import org.onosproject.store.service.LogicalClockService;
47import org.onosproject.store.service.StorageService;
48import org.slf4j.Logger;
49import org.slf4j.LoggerFactory;
50
51import java.util.Map;
nitinanand920fcb42018-05-18 17:30:36 +053052import java.util.Objects;
kdarapu97843dc2018-05-10 12:46:32 +053053import java.util.concurrent.Executors;
54import java.util.concurrent.ScheduledExecutorService;
55import java.util.concurrent.ScheduledFuture;
56import java.util.concurrent.TimeUnit;
57import java.util.stream.Collectors;
nitinanand920fcb42018-05-18 17:30:36 +053058import java.util.Dictionary;
59import static org.onlab.util.Tools.getIntegerProperty;
60
kdarapu97843dc2018-05-10 12:46:32 +053061
62@Service
63@Component(immediate = true)
64public class NodeMetricsManager implements NodeMetricsService {
65 private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 15;
66 private static final String SLASH = "/";
67 private static final Double PERCENTAGE_MULTIPLIER = 100.0;
68 private final Logger log = LoggerFactory
69 .getLogger(this.getClass());
70
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected CoreService coreService;
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected StorageService storageService;
76
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected ClusterService clusterService;
79
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 protected LogicalClockService clockService;
82
nitinanand920fcb42018-05-18 17:30:36 +053083 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected ComponentConfigService cfgService;
85
kdarapu97843dc2018-05-10 12:46:32 +053086 private ScheduledExecutorService metricsExecutor;
87 private ScheduledFuture<?> scheduledTask;
88
89 private ApplicationId appId;
90 private NodeId localNodeId;
91
nitinanand920fcb42018-05-18 17:30:36 +053092 private EventuallyConsistentMap<NodeId, NodeMemoryUsage> memoryStore;
kdarapu97843dc2018-05-10 12:46:32 +053093 private EventuallyConsistentMap<NodeId, NodeDiskUsage> diskStore;
nitinanand920fcb42018-05-18 17:30:36 +053094 private EventuallyConsistentMap<NodeId, NodeCpuUsage> cpuStore;
kdarapu97843dc2018-05-10 12:46:32 +053095
96 private Sigar sigar;
97
nitinanand920fcb42018-05-18 17:30:36 +053098 @Property(name = "metricPollFrequencySeconds", intValue = DEFAULT_POLL_FREQUENCY_SECONDS,
99 label = "Frequency (in seconds) for polling controller metrics")
100 protected int metricPollFrequencySeconds = DEFAULT_POLL_FREQUENCY_SECONDS;
101
kdarapu97843dc2018-05-10 12:46:32 +0530102 @Activate
nitinanand920fcb42018-05-18 17:30:36 +0530103 public void activate(ComponentContext context) {
kdarapu97843dc2018-05-10 12:46:32 +0530104 appId = coreService
105 .registerApplication("org.onosproject.nodemetrics");
nitinanand920fcb42018-05-18 17:30:36 +0530106 cfgService.registerProperties(getClass());
kdarapu97843dc2018-05-10 12:46:32 +0530107 metricsExecutor = Executors.newSingleThreadScheduledExecutor(
108 Tools.groupedThreads("nodemetrics/pollingStatics",
109 "statistics-executor-%d", log));
110
111 localNodeId = clusterService.getLocalNode().id();
112 KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
113 .register(KryoNamespaces.API)
nitinanand920fcb42018-05-18 17:30:36 +0530114 .register(NodeMemoryUsage.class)
kdarapu97843dc2018-05-10 12:46:32 +0530115 .register(NodeDiskUsage.class)
nitinanand920fcb42018-05-18 17:30:36 +0530116 .register(NodeCpuUsage.class)
kdarapu97843dc2018-05-10 12:46:32 +0530117 .register(Units.class);
nitinanand920fcb42018-05-18 17:30:36 +0530118 memoryStore = storageService.<NodeId, NodeMemoryUsage>eventuallyConsistentMapBuilder()
kdarapu97843dc2018-05-10 12:46:32 +0530119 .withSerializer(serializer)
120 .withTimestampProvider((nodeId, memory) -> clockService.getTimestamp())
121 .withName("nodemetrics-memory")
122 .build();
123
124 diskStore = storageService.<NodeId, NodeDiskUsage>eventuallyConsistentMapBuilder()
125 .withSerializer(serializer)
126 .withTimestampProvider((nodeId, disk) -> clockService.getTimestamp())
127 .withName("nodemetrics-disk")
128 .build();
129
nitinanand920fcb42018-05-18 17:30:36 +0530130 cpuStore = storageService.<NodeId, NodeCpuUsage>eventuallyConsistentMapBuilder()
kdarapu97843dc2018-05-10 12:46:32 +0530131 .withSerializer(serializer)
132 .withTimestampProvider((nodeId, cpu) -> clockService.getTimestamp())
133 .withName("nodemetrics-cpu")
134 .build();
nitinanand920fcb42018-05-18 17:30:36 +0530135 modified(context);
kdarapu97843dc2018-05-10 12:46:32 +0530136 sigar = new Sigar();
137 pollMetrics();
138 }
139
140 @Deactivate
141 public void deactivate() {
nitinanand920fcb42018-05-18 17:30:36 +0530142 cfgService.unregisterProperties(getClass(), false);
kdarapu97843dc2018-05-10 12:46:32 +0530143 scheduledTask.cancel(true);
144 metricsExecutor.shutdown();
145 sigar.close();
146 }
147
nitinanand920fcb42018-05-18 17:30:36 +0530148 @Modified
149 public void modified(ComponentContext context) {
150 if (context == null) {
151 log.info("No component configuration");
152 return;
153 }
154
155 Dictionary<?, ?> properties = context.getProperties();
156 int newPollFrequency = getNewPollFrequency(properties);
157 //First time call to this modified method is when app activates
158 if (Objects.isNull(scheduledTask)) {
159 metricPollFrequencySeconds = newPollFrequency;
160 scheduledTask = schedulePolling();
161 } else {
162 if (newPollFrequency != metricPollFrequencySeconds) {
163 metricPollFrequencySeconds = newPollFrequency;
164 //stops the old scheduled task
165 scheduledTask.cancel(true);
166 //schedules new task at the new polling rate
167 scheduledTask = schedulePolling();
168 }
169 }
170 }
171
kdarapu97843dc2018-05-10 12:46:32 +0530172 @Override
nitinanand920fcb42018-05-18 17:30:36 +0530173 public Map<NodeId, NodeMemoryUsage> memory() {
kdarapu97843dc2018-05-10 12:46:32 +0530174 return this.ecToMap(memoryStore);
175 }
176
177 @Override
178 public Map<NodeId, NodeDiskUsage> disk() {
179 return this.ecToMap(diskStore);
180 }
181
182 @Override
nitinanand920fcb42018-05-18 17:30:36 +0530183 public Map<NodeId, NodeCpuUsage> cpu() {
kdarapu97843dc2018-05-10 12:46:32 +0530184 return this.ecToMap(cpuStore);
185 }
186
187 @Override
nitinanand920fcb42018-05-18 17:30:36 +0530188 public NodeMemoryUsage memory(NodeId nodeid) {
kdarapu97843dc2018-05-10 12:46:32 +0530189 return memoryStore.get(nodeid);
190 }
191
192 @Override
193 public NodeDiskUsage disk(NodeId nodeid) {
194 return diskStore.get(nodeid);
195 }
196
197 @Override
nitinanand920fcb42018-05-18 17:30:36 +0530198 public NodeCpuUsage cpu(NodeId nodeid) {
kdarapu97843dc2018-05-10 12:46:32 +0530199 return cpuStore.get(nodeid);
200 }
201
202 private ScheduledFuture schedulePolling() {
203 return metricsExecutor.scheduleAtFixedRate(this::pollMetrics,
nitinanand920fcb42018-05-18 17:30:36 +0530204 metricPollFrequencySeconds / 4,
205 metricPollFrequencySeconds, TimeUnit.SECONDS);
206 }
207
208 private int getNewPollFrequency(Dictionary<?, ?> properties) {
209 int newPollFrequency;
210 try {
211 newPollFrequency = getIntegerProperty(properties, "metricPollFrequencySeconds");
212 //String s = getIntegerProperty(properties, "metricPollFrequencySeconds");
213 //newPollFrequency = isNullOrEmpty(s) ? pollFrequency : Integer.parseInt(s.trim());
214 } catch (NumberFormatException | ClassCastException e) {
215 newPollFrequency = DEFAULT_POLL_FREQUENCY_SECONDS;
216 }
217 return newPollFrequency;
kdarapu97843dc2018-05-10 12:46:32 +0530218 }
219
220 private <K, V> Map<K, V> ecToMap(EventuallyConsistentMap<K, V> ecMap) {
221 return ecMap.entrySet()
222 .stream()
223 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
224 }
nitinanand920fcb42018-05-18 17:30:36 +0530225
kdarapu97843dc2018-05-10 12:46:32 +0530226 private void pollMetrics() {
227 try {
228 CpuPerc cpu = sigar.getCpuPerc();
229 Mem mem = sigar.getMem();
230 FileSystemUsage disk = sigar.getFileSystemUsage(SLASH);
231
nitinanand920fcb42018-05-18 17:30:36 +0530232 NodeMemoryUsage memoryNode = new NodeMemoryUsage.Builder().free(mem.getFree())
kdarapu97843dc2018-05-10 12:46:32 +0530233 .used(mem.getUsed()).total(mem.getTotal()).withUnit(Units.BYTES)
234 .withNode(localNodeId).build();
nitinanand920fcb42018-05-18 17:30:36 +0530235 NodeCpuUsage cpuNode = new NodeCpuUsage.Builder().withNode(localNodeId)
kdarapu97843dc2018-05-10 12:46:32 +0530236 .usage(cpu.getCombined() * PERCENTAGE_MULTIPLIER).build();
237 NodeDiskUsage diskNode = new NodeDiskUsage.Builder().withNode(localNodeId)
238 .free(disk.getFree()).used(disk.getUsed()).withUnit(Units.KBYTES)
239 .total(disk.getTotal()).build();
240 diskStore.put(localNodeId, diskNode);
241 memoryStore.put(localNodeId, memoryNode);
242 cpuStore.put(localNodeId, cpuNode);
243
244 } catch (SigarException e) {
245 log.error("Exception occurred ", e);
246 }
247
248 }
249}