blob: eec2c65bb7b6914f4197a0127bc06ef63fc0069c [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;
Ray Milkey4694e062018-10-31 13:17:18 -070059import static org.onosproject.nodemetrics.impl.OsgiPropertyConstants.METRIC_POLL_FREQUENCY_SECONDS;
60import static org.onosproject.nodemetrics.impl.OsgiPropertyConstants.METRIC_POLL_FREQUENCY_SECONDS_DEFAULT;
nitinanand920fcb42018-05-18 17:30:36 +053061
kdarapu97843dc2018-05-10 12:46:32 +053062
Ray Milkey4694e062018-10-31 13:17:18 -070063@Component(
64 immediate = true,
65 service = NodeMetricsService.class,
66 property = {
67 METRIC_POLL_FREQUENCY_SECONDS + ":Integer=" + METRIC_POLL_FREQUENCY_SECONDS_DEFAULT
68 }
69)
kdarapu97843dc2018-05-10 12:46:32 +053070public class NodeMetricsManager implements NodeMetricsService {
Ray Milkey4694e062018-10-31 13:17:18 -070071
kdarapu97843dc2018-05-10 12:46:32 +053072 private static final String SLASH = "/";
73 private static final Double PERCENTAGE_MULTIPLIER = 100.0;
74 private final Logger log = LoggerFactory
75 .getLogger(this.getClass());
76
Ray Milkeyd84f89b2018-08-17 14:54:17 -070077 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kdarapu97843dc2018-05-10 12:46:32 +053078 protected CoreService coreService;
79
Ray Milkeyd84f89b2018-08-17 14:54:17 -070080 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kdarapu97843dc2018-05-10 12:46:32 +053081 protected StorageService storageService;
82
Ray Milkeyd84f89b2018-08-17 14:54:17 -070083 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kdarapu97843dc2018-05-10 12:46:32 +053084 protected ClusterService clusterService;
85
Ray Milkeyd84f89b2018-08-17 14:54:17 -070086 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kdarapu97843dc2018-05-10 12:46:32 +053087 protected LogicalClockService clockService;
88
Ray Milkeyd84f89b2018-08-17 14:54:17 -070089 @Reference(cardinality = ReferenceCardinality.MANDATORY)
nitinanand920fcb42018-05-18 17:30:36 +053090 protected ComponentConfigService cfgService;
91
kdarapu97843dc2018-05-10 12:46:32 +053092 private ScheduledExecutorService metricsExecutor;
93 private ScheduledFuture<?> scheduledTask;
94
95 private ApplicationId appId;
96 private NodeId localNodeId;
97
nitinanand920fcb42018-05-18 17:30:36 +053098 private EventuallyConsistentMap<NodeId, NodeMemoryUsage> memoryStore;
kdarapu97843dc2018-05-10 12:46:32 +053099 private EventuallyConsistentMap<NodeId, NodeDiskUsage> diskStore;
nitinanand920fcb42018-05-18 17:30:36 +0530100 private EventuallyConsistentMap<NodeId, NodeCpuUsage> cpuStore;
kdarapu97843dc2018-05-10 12:46:32 +0530101
102 private Sigar sigar;
103
Ray Milkey4694e062018-10-31 13:17:18 -0700104 /** Frequency (in seconds) for polling controller metrics. */
105 protected int metricPollFrequencySeconds = METRIC_POLL_FREQUENCY_SECONDS_DEFAULT;
nitinanand920fcb42018-05-18 17:30:36 +0530106
kdarapu97843dc2018-05-10 12:46:32 +0530107 @Activate
nitinanand920fcb42018-05-18 17:30:36 +0530108 public void activate(ComponentContext context) {
kdarapu97843dc2018-05-10 12:46:32 +0530109 appId = coreService
110 .registerApplication("org.onosproject.nodemetrics");
nitinanand920fcb42018-05-18 17:30:36 +0530111 cfgService.registerProperties(getClass());
kdarapu97843dc2018-05-10 12:46:32 +0530112 metricsExecutor = Executors.newSingleThreadScheduledExecutor(
113 Tools.groupedThreads("nodemetrics/pollingStatics",
114 "statistics-executor-%d", log));
115
116 localNodeId = clusterService.getLocalNode().id();
117 KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
118 .register(KryoNamespaces.API)
nitinanand920fcb42018-05-18 17:30:36 +0530119 .register(NodeMemoryUsage.class)
kdarapu97843dc2018-05-10 12:46:32 +0530120 .register(NodeDiskUsage.class)
nitinanand920fcb42018-05-18 17:30:36 +0530121 .register(NodeCpuUsage.class)
kdarapu97843dc2018-05-10 12:46:32 +0530122 .register(Units.class);
nitinanand920fcb42018-05-18 17:30:36 +0530123 memoryStore = storageService.<NodeId, NodeMemoryUsage>eventuallyConsistentMapBuilder()
kdarapu97843dc2018-05-10 12:46:32 +0530124 .withSerializer(serializer)
125 .withTimestampProvider((nodeId, memory) -> clockService.getTimestamp())
126 .withName("nodemetrics-memory")
127 .build();
128
129 diskStore = storageService.<NodeId, NodeDiskUsage>eventuallyConsistentMapBuilder()
130 .withSerializer(serializer)
131 .withTimestampProvider((nodeId, disk) -> clockService.getTimestamp())
132 .withName("nodemetrics-disk")
133 .build();
134
nitinanand920fcb42018-05-18 17:30:36 +0530135 cpuStore = storageService.<NodeId, NodeCpuUsage>eventuallyConsistentMapBuilder()
kdarapu97843dc2018-05-10 12:46:32 +0530136 .withSerializer(serializer)
137 .withTimestampProvider((nodeId, cpu) -> clockService.getTimestamp())
138 .withName("nodemetrics-cpu")
139 .build();
nitinanand920fcb42018-05-18 17:30:36 +0530140 modified(context);
kdarapu97843dc2018-05-10 12:46:32 +0530141 sigar = new Sigar();
142 pollMetrics();
143 }
144
145 @Deactivate
146 public void deactivate() {
nitinanand920fcb42018-05-18 17:30:36 +0530147 cfgService.unregisterProperties(getClass(), false);
kdarapu97843dc2018-05-10 12:46:32 +0530148 scheduledTask.cancel(true);
149 metricsExecutor.shutdown();
150 sigar.close();
151 }
152
nitinanand920fcb42018-05-18 17:30:36 +0530153 @Modified
154 public void modified(ComponentContext context) {
155 if (context == null) {
156 log.info("No component configuration");
157 return;
158 }
159
160 Dictionary<?, ?> properties = context.getProperties();
161 int newPollFrequency = getNewPollFrequency(properties);
162 //First time call to this modified method is when app activates
163 if (Objects.isNull(scheduledTask)) {
164 metricPollFrequencySeconds = newPollFrequency;
165 scheduledTask = schedulePolling();
166 } else {
167 if (newPollFrequency != metricPollFrequencySeconds) {
168 metricPollFrequencySeconds = newPollFrequency;
169 //stops the old scheduled task
170 scheduledTask.cancel(true);
171 //schedules new task at the new polling rate
172 scheduledTask = schedulePolling();
173 }
174 }
175 }
176
kdarapu97843dc2018-05-10 12:46:32 +0530177 @Override
nitinanand920fcb42018-05-18 17:30:36 +0530178 public Map<NodeId, NodeMemoryUsage> memory() {
kdarapu97843dc2018-05-10 12:46:32 +0530179 return this.ecToMap(memoryStore);
180 }
181
182 @Override
183 public Map<NodeId, NodeDiskUsage> disk() {
184 return this.ecToMap(diskStore);
185 }
186
187 @Override
nitinanand920fcb42018-05-18 17:30:36 +0530188 public Map<NodeId, NodeCpuUsage> cpu() {
kdarapu97843dc2018-05-10 12:46:32 +0530189 return this.ecToMap(cpuStore);
190 }
191
192 @Override
nitinanand920fcb42018-05-18 17:30:36 +0530193 public NodeMemoryUsage memory(NodeId nodeid) {
kdarapu97843dc2018-05-10 12:46:32 +0530194 return memoryStore.get(nodeid);
195 }
196
197 @Override
198 public NodeDiskUsage disk(NodeId nodeid) {
199 return diskStore.get(nodeid);
200 }
201
202 @Override
nitinanand920fcb42018-05-18 17:30:36 +0530203 public NodeCpuUsage cpu(NodeId nodeid) {
kdarapu97843dc2018-05-10 12:46:32 +0530204 return cpuStore.get(nodeid);
205 }
206
207 private ScheduledFuture schedulePolling() {
208 return metricsExecutor.scheduleAtFixedRate(this::pollMetrics,
nitinanand920fcb42018-05-18 17:30:36 +0530209 metricPollFrequencySeconds / 4,
210 metricPollFrequencySeconds, TimeUnit.SECONDS);
211 }
212
213 private int getNewPollFrequency(Dictionary<?, ?> properties) {
214 int newPollFrequency;
215 try {
Ray Milkey4694e062018-10-31 13:17:18 -0700216 newPollFrequency = getIntegerProperty(properties, METRIC_POLL_FREQUENCY_SECONDS);
nitinanand920fcb42018-05-18 17:30:36 +0530217 //String s = getIntegerProperty(properties, "metricPollFrequencySeconds");
218 //newPollFrequency = isNullOrEmpty(s) ? pollFrequency : Integer.parseInt(s.trim());
219 } catch (NumberFormatException | ClassCastException e) {
Ray Milkey4694e062018-10-31 13:17:18 -0700220 newPollFrequency = METRIC_POLL_FREQUENCY_SECONDS_DEFAULT;
nitinanand920fcb42018-05-18 17:30:36 +0530221 }
222 return newPollFrequency;
kdarapu97843dc2018-05-10 12:46:32 +0530223 }
224
225 private <K, V> Map<K, V> ecToMap(EventuallyConsistentMap<K, V> ecMap) {
226 return ecMap.entrySet()
227 .stream()
228 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
229 }
nitinanand920fcb42018-05-18 17:30:36 +0530230
kdarapu97843dc2018-05-10 12:46:32 +0530231 private void pollMetrics() {
232 try {
233 CpuPerc cpu = sigar.getCpuPerc();
234 Mem mem = sigar.getMem();
235 FileSystemUsage disk = sigar.getFileSystemUsage(SLASH);
236
nitinanand920fcb42018-05-18 17:30:36 +0530237 NodeMemoryUsage memoryNode = new NodeMemoryUsage.Builder().free(mem.getFree())
kdarapu97843dc2018-05-10 12:46:32 +0530238 .used(mem.getUsed()).total(mem.getTotal()).withUnit(Units.BYTES)
239 .withNode(localNodeId).build();
nitinanand920fcb42018-05-18 17:30:36 +0530240 NodeCpuUsage cpuNode = new NodeCpuUsage.Builder().withNode(localNodeId)
kdarapu97843dc2018-05-10 12:46:32 +0530241 .usage(cpu.getCombined() * PERCENTAGE_MULTIPLIER).build();
242 NodeDiskUsage diskNode = new NodeDiskUsage.Builder().withNode(localNodeId)
243 .free(disk.getFree()).used(disk.getUsed()).withUnit(Units.KBYTES)
244 .total(disk.getTotal()).build();
245 diskStore.put(localNodeId, diskNode);
246 memoryStore.put(localNodeId, memoryNode);
247 cpuStore.put(localNodeId, cpuNode);
248
249 } catch (SigarException e) {
250 log.error("Exception occurred ", e);
251 }
252
253 }
254}