blob: 7f6d9e829b6f2641a4214de7cca40146bbf2d62b [file] [log] [blame]
Andrea Campanella945ded22016-01-07 13:17:43 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Andrea Campanella945ded22016-01-07 13:17:43 -08003 *
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 */
16
17package org.onosproject.provider.rest.device.impl;
18
Konstantinos Kanonakis3cd85552016-11-17 10:11:13 -060019import com.google.common.base.Objects;
Andrea Campanella59b549d2017-04-14 21:58:16 +020020import com.google.common.collect.ImmutableList;
Andrea Campanella945ded22016-01-07 13:17:43 -080021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.onlab.packet.ChassisId;
Michal Machd8099742017-06-19 14:32:35 +020027import org.onlab.util.SharedScheduledExecutorService;
28import org.onlab.util.SharedScheduledExecutors;
Andrea Campanella945ded22016-01-07 13:17:43 -080029import org.onosproject.core.ApplicationId;
30import org.onosproject.core.CoreService;
Marc De Leenheerb0d131c2016-03-01 20:34:59 -080031import org.onosproject.net.AnnotationKeys;
Andrea Campanella945ded22016-01-07 13:17:43 -080032import org.onosproject.net.DefaultAnnotations;
33import org.onosproject.net.Device;
34import org.onosproject.net.DeviceId;
35import org.onosproject.net.MastershipRole;
Saurav Dasa2d37502016-03-25 17:50:40 -070036import org.onosproject.net.PortNumber;
Andrea Campanella945ded22016-01-07 13:17:43 -080037import org.onosproject.net.SparseAnnotations;
Michele Santuaric372c222017-01-12 09:41:25 +010038import org.onosproject.net.behaviour.DevicesDiscovery;
fahadnaeemkhan02ffa712017-12-01 19:49:45 -080039import org.onosproject.net.behaviour.PortAdmin;
Andrea Campanellad8d92db2016-01-14 16:24:41 -080040import org.onosproject.net.behaviour.PortDiscovery;
fahadnaeemkhan02ffa712017-12-01 19:49:45 -080041import org.onosproject.net.config.ConfigException;
Andrea Campanella945ded22016-01-07 13:17:43 -080042import org.onosproject.net.config.ConfigFactory;
43import org.onosproject.net.config.NetworkConfigEvent;
44import org.onosproject.net.config.NetworkConfigListener;
45import org.onosproject.net.config.NetworkConfigRegistry;
Andrea Campanella59b549d2017-04-14 21:58:16 +020046import org.onosproject.net.config.basics.SubjectFactories;
Andrea Campanella945ded22016-01-07 13:17:43 -080047import org.onosproject.net.device.DefaultDeviceDescription;
48import org.onosproject.net.device.DeviceDescription;
Andrea Campanella6c71a052016-04-22 11:56:31 -070049import org.onosproject.net.device.DeviceDescriptionDiscovery;
Andrea Campanella945ded22016-01-07 13:17:43 -080050import org.onosproject.net.device.DeviceProvider;
51import org.onosproject.net.device.DeviceProviderRegistry;
52import org.onosproject.net.device.DeviceProviderService;
Andrea Campanella6c71a052016-04-22 11:56:31 -070053import org.onosproject.net.device.DeviceService;
Michal Machd8099742017-06-19 14:32:35 +020054import org.onosproject.net.device.PortStatistics;
55import org.onosproject.net.device.PortStatisticsDiscovery;
Michele Santuaric372c222017-01-12 09:41:25 +010056import org.onosproject.net.driver.DefaultDriverData;
57import org.onosproject.net.driver.DefaultDriverHandler;
58import org.onosproject.net.driver.Driver;
59import org.onosproject.net.driver.DriverData;
60import org.onosproject.net.driver.DriverHandler;
61import org.onosproject.net.driver.DriverService;
Andrea Campanella945ded22016-01-07 13:17:43 -080062import org.onosproject.net.provider.AbstractProvider;
63import org.onosproject.net.provider.ProviderId;
Andrea Campanella59b549d2017-04-14 21:58:16 +020064import org.onosproject.protocol.rest.DefaultRestSBDevice;
Andrea Campanella945ded22016-01-07 13:17:43 -080065import org.onosproject.protocol.rest.RestSBController;
66import org.onosproject.protocol.rest.RestSBDevice;
67import org.slf4j.Logger;
68
Andrea Campanellac6ecc632016-03-10 17:57:06 -080069import javax.ws.rs.ProcessingException;
Michal Mach67acb692017-06-21 12:05:36 +020070import javax.ws.rs.core.MediaType;
Michal Machd8099742017-06-19 14:32:35 +020071import java.util.Collection;
Andrea Campanella945ded22016-01-07 13:17:43 -080072import java.util.HashSet;
Andrea Campanella59b549d2017-04-14 21:58:16 +020073import java.util.List;
Andrea Campanella945ded22016-01-07 13:17:43 -080074import java.util.Set;
Palash Kala4c71ee72017-05-24 17:43:59 +090075import java.util.concurrent.Callable;
fahadnaeemkhan02ffa712017-12-01 19:49:45 -080076import java.util.concurrent.CompletableFuture;
Palash Kala4c71ee72017-05-24 17:43:59 +090077import java.util.concurrent.ExecutionException;
Andrea Campanella784ee0f2016-02-17 15:50:59 -080078import java.util.concurrent.ExecutorService;
79import java.util.concurrent.Executors;
Palash Kala4c71ee72017-05-24 17:43:59 +090080import java.util.concurrent.Future;
Michal Machd8099742017-06-19 14:32:35 +020081import java.util.concurrent.ScheduledFuture;
Palash Kala4c71ee72017-05-24 17:43:59 +090082import java.util.concurrent.TimeUnit;
83import java.util.concurrent.TimeoutException;
Andrea Campanella59b549d2017-04-14 21:58:16 +020084import java.util.stream.Collectors;
Andrea Campanella945ded22016-01-07 13:17:43 -080085
Michele Santuaric372c222017-01-12 09:41:25 +010086import static com.google.common.base.Preconditions.checkNotNull;
Andrea Campanella784ee0f2016-02-17 15:50:59 -080087import static org.onlab.util.Tools.groupedThreads;
Andrea Campanella945ded22016-01-07 13:17:43 -080088import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_ADDED;
89import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UPDATED;
90import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
91import static org.slf4j.LoggerFactory.getLogger;
92
93/**
94 * Provider for devices that use REST as means of configuration communication.
95 */
96@Component(immediate = true)
97public class RestDeviceProvider extends AbstractProvider
98 implements DeviceProvider {
99 private static final String APP_NAME = "org.onosproject.restsb";
Andrea Campanella59b549d2017-04-14 21:58:16 +0200100 protected static final String REST = "rest";
Andrea Campanella945ded22016-01-07 13:17:43 -0800101 private static final String PROVIDER = "org.onosproject.provider.rest.device";
102 private static final String IPADDRESS = "ipaddress";
Michal Mach67acb692017-06-21 12:05:36 +0200103 private static final String ISNOTNULL = "Rest device is not null";
Michele Santuaric372c222017-01-12 09:41:25 +0100104 private static final String UNKNOWN = "unknown";
Palash Kala4c71ee72017-05-24 17:43:59 +0900105 private static final int REST_TIMEOUT_SEC = 5;
Michal Machd8099742017-06-19 14:32:35 +0200106 private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 30;
Georgios Katsikas6a4d1662017-07-27 13:22:31 +0200107 private static final int EXECUTOR_THREAD_POOL_SIZE = 8;
Andrea Campanella945ded22016-01-07 13:17:43 -0800108 private final Logger log = getLogger(getClass());
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected DeviceProviderRegistry providerRegistry;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected RestSBController controller;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected NetworkConfigRegistry cfgService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected CoreService coreService;
121
Andrea Campanellad8d92db2016-01-14 16:24:41 -0800122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanella6c71a052016-04-22 11:56:31 -0700123 protected DeviceService deviceService;
Andrea Campanellad8d92db2016-01-14 16:24:41 -0800124
Michele Santuaric372c222017-01-12 09:41:25 +0100125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected DriverService driverService;
127
Andrea Campanella945ded22016-01-07 13:17:43 -0800128 private DeviceProviderService providerService;
Michele Santuaric372c222017-01-12 09:41:25 +0100129 private ApplicationId appId;
Andrea Campanella945ded22016-01-07 13:17:43 -0800130
Michal Mach13072e22017-06-21 09:12:24 +0200131 private ExecutorService executor;
Michal Mach67acb692017-06-21 12:05:36 +0200132 private final SharedScheduledExecutorService portStatisticsExecutor =
133 SharedScheduledExecutors.getPoolThreadExecutor();
Andrea Campanella784ee0f2016-02-17 15:50:59 -0800134
Michal Mach67acb692017-06-21 12:05:36 +0200135 private final List<ConfigFactory> factories = ImmutableList.of(
Andrea Campanella945ded22016-01-07 13:17:43 -0800136 new ConfigFactory<ApplicationId, RestProviderConfig>(APP_SUBJECT_FACTORY,
137 RestProviderConfig.class,
Palash Kalac3ffad92017-06-09 21:18:19 +0900138 "rest_devices",
Andrea Campanella945ded22016-01-07 13:17:43 -0800139 true) {
140 @Override
141 public RestProviderConfig createConfig() {
142 return new RestProviderConfig();
143 }
Andrea Campanella59b549d2017-04-14 21:58:16 +0200144 },
145 new ConfigFactory<DeviceId, RestDeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
146 RestDeviceConfig.class,
147 REST) {
148 @Override
149 public RestDeviceConfig createConfig() {
150 return new RestDeviceConfig();
151 }
152 });
153
Michal Mach67acb692017-06-21 12:05:36 +0200154 private final NetworkConfigListener configListener = new InternalNetworkConfigListener();
Andrea Campanella945ded22016-01-07 13:17:43 -0800155
Michal Machd8099742017-06-19 14:32:35 +0200156 private ScheduledFuture<?> scheduledTask;
Andrea Campanella784ee0f2016-02-17 15:50:59 -0800157
Andrea Campanella945ded22016-01-07 13:17:43 -0800158
159 @Activate
160 public void activate() {
161 appId = coreService.registerApplication(APP_NAME);
162 providerService = providerRegistry.register(this);
Andrea Campanella59b549d2017-04-14 21:58:16 +0200163 factories.forEach(cfgService::registerConfigFactory);
Georgios Katsikas6a4d1662017-07-27 13:22:31 +0200164 executor = Executors.newFixedThreadPool(
165 EXECUTOR_THREAD_POOL_SIZE, groupedThreads("onos/restsbprovider", "device-installer-%d", log)
166 );
Michal Mach67acb692017-06-21 12:05:36 +0200167 cfgService.addListener(configListener);
Andrea Campanella59b549d2017-04-14 21:58:16 +0200168 executor.execute(RestDeviceProvider.this::createAndConnectDevices);
169 executor.execute(RestDeviceProvider.this::createDevices);
Michal Machd8099742017-06-19 14:32:35 +0200170 scheduledTask = schedulePolling();
Andrea Campanella945ded22016-01-07 13:17:43 -0800171 log.info("Started");
172 }
173
Andrea Campanella945ded22016-01-07 13:17:43 -0800174 @Deactivate
175 public void deactivate() {
Michal Mach67acb692017-06-21 12:05:36 +0200176 cfgService.removeListener(configListener);
Andrea Campanella86294db2016-03-07 11:42:49 -0800177 controller.getDevices().keySet().forEach(this::deviceRemoved);
Andrea Campanella945ded22016-01-07 13:17:43 -0800178 providerRegistry.unregister(this);
179 providerService = null;
Andrea Campanella59b549d2017-04-14 21:58:16 +0200180 factories.forEach(cfgService::unregisterConfigFactory);
Michal Machd8099742017-06-19 14:32:35 +0200181 scheduledTask.cancel(true);
Lukasz Ryba4da35c52017-06-20 09:14:11 +0200182 executor.shutdown();
Andrea Campanella945ded22016-01-07 13:17:43 -0800183 log.info("Stopped");
184 }
185
186 public RestDeviceProvider() {
187 super(new ProviderId(REST, PROVIDER));
188 }
189
190 @Override
191 public void triggerProbe(DeviceId deviceId) {
192 // TODO: This will be implemented later.
193 log.info("Triggering probe on device {}", deviceId);
194 }
195
196 @Override
197 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
198 // TODO: This will be implemented later.
199 }
200
Andrea Campanella945ded22016-01-07 13:17:43 -0800201 @Override
202 public boolean isReachable(DeviceId deviceId) {
203 RestSBDevice restDevice = controller.getDevice(deviceId);
204 if (restDevice == null) {
Michele Santuaric372c222017-01-12 09:41:25 +0100205 restDevice = controller.getProxySBDevice(deviceId);
206 if (restDevice == null) {
207 log.debug("the requested device id: " +
208 deviceId.toString() +
209 " is not associated to any REST or REST " +
210 "proxy Device");
211 return false;
212 }
Andrea Campanella945ded22016-01-07 13:17:43 -0800213 }
214 return restDevice.isActive();
215 }
216
Michele Santuaric372c222017-01-12 09:41:25 +0100217 private void deviceAdded(RestSBDevice restSBDev) {
218 checkNotNull(restSBDev, ISNOTNULL);
219
220 //check if the server is controlling a single or multiple devices
221 if (restSBDev.isProxy()) {
222
223 Driver driver = driverService.getDriver(restSBDev.manufacturer().get(),
224 restSBDev.hwVersion().get(),
225 restSBDev.swVersion().get());
226
227 if (driver != null && driver.hasBehaviour(DevicesDiscovery.class)) {
228
229 //Creates the driver to communicate with the server
230 DevicesDiscovery devicesDiscovery =
231 devicesDiscovery(restSBDev, driver);
232 Set<DeviceId> deviceIds = devicesDiscovery.deviceIds();
233 restSBDev.setActive(true);
Michal Mach67acb692017-06-21 12:05:36 +0200234 deviceIds.forEach(deviceId -> {
Michele Santuaric372c222017-01-12 09:41:25 +0100235 controller.addProxiedDevice(deviceId, restSBDev);
236 DeviceDescription devDesc =
237 devicesDiscovery.deviceDetails(deviceId);
238 checkNotNull(devDesc,
239 "deviceDescription cannot be null");
240 providerService.deviceConnected(
241 deviceId, mergeAnn(restSBDev.deviceId(), devDesc));
242
243 if (driver.hasBehaviour(DeviceDescriptionDiscovery.class)) {
244 DriverHandler h = driverService.createHandler(deviceId);
245 DeviceDescriptionDiscovery devDisc =
246 h.behaviour(DeviceDescriptionDiscovery.class);
247 providerService.updatePorts(deviceId,
248 devDisc.discoverPortDetails());
249 }
250
251 checkAndUpdateDevice(deviceId);
Michele Santuaric372c222017-01-12 09:41:25 +0100252 });
253 } else {
254 log.warn("Driver not found for {}", restSBDev);
255 }
256 } else {
257 DeviceId deviceId = restSBDev.deviceId();
258 ChassisId cid = new ChassisId();
259 String ipAddress = restSBDev.ip().toString();
260 SparseAnnotations annotations = DefaultAnnotations.builder()
261 .set(IPADDRESS, ipAddress)
262 .set(AnnotationKeys.PROTOCOL, REST.toUpperCase())
263 .build();
264 DeviceDescription deviceDescription = new DefaultDeviceDescription(
265 deviceId.uri(),
266 Device.Type.SWITCH,
267 UNKNOWN, UNKNOWN,
268 UNKNOWN, UNKNOWN,
269 cid,
270 annotations);
271 restSBDev.setActive(true);
272 providerService.deviceConnected(deviceId, deviceDescription);
273 checkAndUpdateDevice(deviceId);
Michele Santuaric372c222017-01-12 09:41:25 +0100274 }
275 }
276
277 private DefaultDeviceDescription mergeAnn(DeviceId devId, DeviceDescription desc) {
278 return new DefaultDeviceDescription(
279 desc,
280 DefaultAnnotations.merge(
281 DefaultAnnotations.builder()
282 .set(AnnotationKeys.PROTOCOL, REST.toUpperCase())
283 // The rest server added as annotation to the device
284 .set(AnnotationKeys.REST_SERVER, devId.toString())
285 .build(),
286 desc.annotations()));
287 }
288
289 private DevicesDiscovery devicesDiscovery(RestSBDevice restSBDevice, Driver driver) {
290 DriverData driverData = new DefaultDriverData(driver, restSBDevice.deviceId());
291 DevicesDiscovery devicesDiscovery = driver.createBehaviour(driverData,
292 DevicesDiscovery.class);
293 devicesDiscovery.setHandler(new DefaultDriverHandler(driverData));
294 return devicesDiscovery;
Andrea Campanella945ded22016-01-07 13:17:43 -0800295 }
296
Konstantinos Kanonakis3cd85552016-11-17 10:11:13 -0600297 private void checkAndUpdateDevice(DeviceId deviceId) {
298 if (deviceService.getDevice(deviceId) == null) {
299 log.warn("Device {} has not been added to store, " +
300 "maybe due to a problem in connectivity", deviceId);
301 } else {
302 boolean isReachable = isReachable(deviceId);
303 if (isReachable && deviceService.isAvailable(deviceId)) {
304 Device device = deviceService.getDevice(deviceId);
305 if (device.is(DeviceDescriptionDiscovery.class)) {
Michele Santuaric372c222017-01-12 09:41:25 +0100306 DeviceDescriptionDiscovery deviceDescriptionDiscovery =
307 device.as(DeviceDescriptionDiscovery.class);
308 DeviceDescription updatedDeviceDescription =
309 deviceDescriptionDiscovery.discoverDeviceDetails();
310 if (updatedDeviceDescription != null &&
311 !descriptionEquals(device, updatedDeviceDescription)) {
312 providerService.deviceConnected(
313 deviceId,
314 new DefaultDeviceDescription(
315 updatedDeviceDescription, true,
316 updatedDeviceDescription.annotations()));
Konstantinos Kanonakis3cd85552016-11-17 10:11:13 -0600317 //if ports are not discovered, retry the discovery
318 if (deviceService.getPorts(deviceId).isEmpty()) {
319 discoverPorts(deviceId);
320 }
321 }
322 } else {
323 log.warn("No DeviceDescriptionDiscovery behaviour for device {}", deviceId);
324 }
325 } else if (!isReachable && deviceService.isAvailable(deviceId)) {
326 providerService.deviceDisconnected(deviceId);
327 }
328 }
329 }
330
331 private boolean descriptionEquals(Device device, DeviceDescription updatedDeviceDescription) {
Michele Santuarid2c8f212017-01-09 18:23:45 +0100332 return Objects.equal(device.id().uri(), updatedDeviceDescription.deviceUri())
Konstantinos Kanonakis3cd85552016-11-17 10:11:13 -0600333 && Objects.equal(device.type(), updatedDeviceDescription.type())
334 && Objects.equal(device.manufacturer(), updatedDeviceDescription.manufacturer())
335 && Objects.equal(device.hwVersion(), updatedDeviceDescription.hwVersion())
336 && Objects.equal(device.swVersion(), updatedDeviceDescription.swVersion())
337 && Objects.equal(device.serialNumber(), updatedDeviceDescription.serialNumber())
338 && Objects.equal(device.chassisId(), updatedDeviceDescription.chassisId())
339 && Objects.equal(device.annotations(), updatedDeviceDescription.annotations());
340 }
341
Andrea Campanella86294db2016-03-07 11:42:49 -0800342 private void deviceRemoved(DeviceId deviceId) {
Michele Santuaric372c222017-01-12 09:41:25 +0100343 checkNotNull(deviceId, ISNOTNULL);
Andrea Campanella945ded22016-01-07 13:17:43 -0800344 providerService.deviceDisconnected(deviceId);
Michal Mach67acb692017-06-21 12:05:36 +0200345 controller.getProxiedDevices(deviceId).forEach(device -> {
Michele Santuaric372c222017-01-12 09:41:25 +0100346 controller.removeProxiedDevice(device);
347 providerService.deviceDisconnected(device);
348 });
Andrea Campanella86294db2016-03-07 11:42:49 -0800349 controller.removeDevice(deviceId);
Andrea Campanella945ded22016-01-07 13:17:43 -0800350 }
351
Andrea Campanella59b549d2017-04-14 21:58:16 +0200352 //Method to connect devices provided via net-cfg under devices/ tree
353 private void createAndConnectDevices() {
354 Set<DeviceId> deviceSubjects =
355 cfgService.getSubjects(DeviceId.class, RestDeviceConfig.class);
356 connectDevices(deviceSubjects.stream()
fahadnaeemkhan02ffa712017-12-01 19:49:45 -0800357 .filter(deviceId -> deviceService.getDevice(deviceId) == null)
358 .map(deviceId -> {
359 RestDeviceConfig config =
360 cfgService.getConfig(deviceId, RestDeviceConfig.class);
361 return new DefaultRestSBDevice(config.ip(),
362 config.port(),
363 config.username(),
364 config.password(),
365 config.protocol(),
366 config.url(),
367 false,
368 config.testUrl(),
369 config.manufacturer(),
370 config.hwVersion(),
371 config.swVersion(),
372 config.authenticationScheme(),
373 config.token()
374 );
375 }).collect(Collectors.toSet()));
Andrea Campanella59b549d2017-04-14 21:58:16 +0200376 }
377
378 //Old method to register devices provided via net-cfg under apps/rest/ tree
379 private void createDevices() {
Andrea Campanella945ded22016-01-07 13:17:43 -0800380 RestProviderConfig cfg = cfgService.getConfig(appId, RestProviderConfig.class);
381 try {
382 if (cfg != null && cfg.getDevicesAddresses() != null) {
Andrea Campanella59b549d2017-04-14 21:58:16 +0200383 connectDevices(cfg.getDevicesAddresses());
384
Andrea Campanella945ded22016-01-07 13:17:43 -0800385 }
386 } catch (ConfigException e) {
387 log.error("Configuration error {}", e);
388 }
Andrea Campanella2947e622016-01-27 09:23:46 -0800389 log.debug("REST Devices {}", controller.getDevices());
Andrea Campanella945ded22016-01-07 13:17:43 -0800390 }
391
Andrea Campanella59b549d2017-04-14 21:58:16 +0200392 private void connectDevices(Set<RestSBDevice> devices) {
393 //Precomputing the devices to be removed
394 Set<RestSBDevice> toBeRemoved = new HashSet<>(controller.getDevices().values());
395 toBeRemoved.removeAll(devices);
396 //Adding new devices
397 devices.stream()
398 .filter(device -> {
399 device.setActive(false);
400 controller.addDevice(device);
401 return testDeviceConnection(device);
402 })
Michal Mach67acb692017-06-21 12:05:36 +0200403 .forEach(this::deviceAdded);
Andrea Campanella59b549d2017-04-14 21:58:16 +0200404 //Removing devices not wanted anymore
405 toBeRemoved.forEach(device -> deviceRemoved(device.deviceId()));
406 }
407
Michal Machd8099742017-06-19 14:32:35 +0200408 private ScheduledFuture schedulePolling() {
409 return portStatisticsExecutor.scheduleAtFixedRate(this::executePortStatisticsUpdate,
410 DEFAULT_POLL_FREQUENCY_SECONDS / 2,
411 DEFAULT_POLL_FREQUENCY_SECONDS,
412 TimeUnit.SECONDS);
413 }
414
415 private void executePortStatisticsUpdate() {
416 controller.getDevices().keySet().forEach(this::updatePortStatistics);
417 }
418
419 private void updatePortStatistics(DeviceId deviceId) {
420 Device device = deviceService.getDevice(deviceId);
421 checkNotNull(device, "device cannot be null");
422
423 if (device.is(PortStatisticsDiscovery.class)) {
424 PortStatisticsDiscovery portStatisticsDiscovery = device.as(PortStatisticsDiscovery.class);
425 Collection<PortStatistics> portStatistics = portStatisticsDiscovery.discoverPortStatistics();
426 if (portStatistics != null && !portStatistics.isEmpty()) {
427 providerService.updatePortStatistics(deviceId, portStatistics);
428 }
429 } else {
430 log.debug("No port statistics getter behaviour for device {}", deviceId);
431 }
432 }
433
Andrea Campanella6c71a052016-04-22 11:56:31 -0700434 private void discoverPorts(DeviceId deviceId) {
435 Device device = deviceService.getDevice(deviceId);
436 //TODO remove when PortDiscovery is removed from master
437 if (device.is(PortDiscovery.class)) {
438 PortDiscovery portConfig = device.as(PortDiscovery.class);
Konstantinos Kanonakis3cd85552016-11-17 10:11:13 -0600439 providerService.updatePorts(deviceId, portConfig.getPorts());
440 } else {
Andrea Campanella6c71a052016-04-22 11:56:31 -0700441 DeviceDescriptionDiscovery deviceDescriptionDiscovery =
442 device.as(DeviceDescriptionDiscovery.class);
443 providerService.updatePorts(deviceId, deviceDescriptionDiscovery.discoverPortDetails());
Andrea Campanella6c71a052016-04-22 11:56:31 -0700444 }
445 }
446
Michele Santuaric372c222017-01-12 09:41:25 +0100447 private boolean testDeviceConnection(RestSBDevice dev) {
Andrea Campanella945ded22016-01-07 13:17:43 -0800448 try {
Palash Kala4c71ee72017-05-24 17:43:59 +0900449 Callable<Boolean> connectionSuccess;
450
Michele Santuaric372c222017-01-12 09:41:25 +0100451 if (dev.testUrl().isPresent()) {
Michal Mach67acb692017-06-21 12:05:36 +0200452 connectionSuccess = () ->
453 controller.get(dev.deviceId(), dev.testUrl().get(), MediaType.APPLICATION_JSON_TYPE) != null;
Palash Kala4c71ee72017-05-24 17:43:59 +0900454 } else {
Michal Mach67acb692017-06-21 12:05:36 +0200455 connectionSuccess = () ->
456 controller.get(dev.deviceId(), "", MediaType.APPLICATION_JSON_TYPE) != null;
Michele Santuaric372c222017-01-12 09:41:25 +0100457 }
Palash Kala4c71ee72017-05-24 17:43:59 +0900458
459 Future<Boolean> future = executor.submit(connectionSuccess);
460 try {
Michal Mach67acb692017-06-21 12:05:36 +0200461 return future.get(REST_TIMEOUT_SEC, TimeUnit.SECONDS);
Palash Kala4c71ee72017-05-24 17:43:59 +0900462 } catch (TimeoutException ex) {
463 log.warn("Connection to device {} timed out", dev.deviceId());
464 return false;
465 } catch (InterruptedException ex) {
466 log.warn("Connection to device {} interrupted", dev.deviceId());
467 return false;
468 } catch (ExecutionException ex) {
469 log.warn("Connection to device {} had a execution exception", dev.deviceId());
470 return false;
471 }
Michele Santuaric372c222017-01-12 09:41:25 +0100472
Andrea Campanellac6ecc632016-03-10 17:57:06 -0800473 } catch (ProcessingException e) {
Michele Santuaric372c222017-01-12 09:41:25 +0100474 log.warn("Cannot connect to device {}", dev, e);
Andrea Campanella945ded22016-01-07 13:17:43 -0800475 }
476 return false;
477 }
478
479 private class InternalNetworkConfigListener implements NetworkConfigListener {
Andrea Campanella945ded22016-01-07 13:17:43 -0800480 @Override
481 public void event(NetworkConfigEvent event) {
Andrea Campanella59b549d2017-04-14 21:58:16 +0200482 if (event.configClass().equals(RestDeviceConfig.class)) {
483 executor.execute(RestDeviceProvider.this::createAndConnectDevices);
484 } else {
485 log.warn("Injecting device via this Json is deprecated, " +
486 "please put configuration under devices/");
487 executor.execute(RestDeviceProvider.this::createDevices);
488 }
Andrea Campanella945ded22016-01-07 13:17:43 -0800489 }
490
491 @Override
492 public boolean isRelevant(NetworkConfigEvent event) {
Andrea Campanella59b549d2017-04-14 21:58:16 +0200493 return (event.configClass().equals(RestDeviceConfig.class) ||
494 event.configClass().equals(RestProviderConfig.class)) &&
Andrea Campanella945ded22016-01-07 13:17:43 -0800495 (event.type() == CONFIG_ADDED ||
496 event.type() == CONFIG_UPDATED);
497 }
498 }
Saurav Dasa2d37502016-03-25 17:50:40 -0700499
500 @Override
501 public void changePortState(DeviceId deviceId, PortNumber portNumber,
502 boolean enable) {
fahadnaeemkhan482951f2017-08-24 16:35:17 -0700503 Device device = deviceService.getDevice(deviceId);
504 if (device != null) {
505 if (device.is(PortAdmin.class)) {
506 PortAdmin portAdmin = device.as(PortAdmin.class);
507 CompletableFuture<Boolean> modified;
508 if (enable) {
509 modified = portAdmin.enable(portNumber);
510 } else {
511 modified = portAdmin.disable(portNumber);
512 }
513 modified.thenAcceptAsync(result -> {
514 if (!result) {
515 log.warn("Device {} port {} state can't be changed to {}",
516 deviceId, portNumber, enable);
517 }
518 });
519
520 } else {
521 log.warn("Device {} does not support PortAdmin behavior", deviceId);
522 }
523 } else {
524 log.warn("unable to get the device {}, port {} state can't be changed to {}",
525 deviceId, portNumber, enable);
526 }
Saurav Dasa2d37502016-03-25 17:50:40 -0700527 }
Andrea Campanella945ded22016-01-07 13:17:43 -0800528}