blob: bb30b3a46e74e1e9e0c8cef49d3a0c1431e861c9 [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;
Yuta HIGUCHIfc667052017-12-05 18:17:22 -080027import org.onlab.util.SharedExecutors;
Michal Machd8099742017-06-19 14:32:35 +020028import org.onlab.util.SharedScheduledExecutorService;
29import org.onlab.util.SharedScheduledExecutors;
Andrea Campanella945ded22016-01-07 13:17:43 -080030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
Marc De Leenheerb0d131c2016-03-01 20:34:59 -080032import org.onosproject.net.AnnotationKeys;
Andrea Campanella945ded22016-01-07 13:17:43 -080033import org.onosproject.net.DefaultAnnotations;
34import org.onosproject.net.Device;
35import org.onosproject.net.DeviceId;
36import org.onosproject.net.MastershipRole;
Saurav Dasa2d37502016-03-25 17:50:40 -070037import org.onosproject.net.PortNumber;
Andrea Campanella945ded22016-01-07 13:17:43 -080038import org.onosproject.net.SparseAnnotations;
Michele Santuaric372c222017-01-12 09:41:25 +010039import org.onosproject.net.behaviour.DevicesDiscovery;
fahadnaeemkhan02ffa712017-12-01 19:49:45 -080040import org.onosproject.net.behaviour.PortAdmin;
Andrea Campanella945ded22016-01-07 13:17:43 -080041import org.onosproject.net.config.ConfigFactory;
42import org.onosproject.net.config.NetworkConfigEvent;
43import org.onosproject.net.config.NetworkConfigListener;
44import org.onosproject.net.config.NetworkConfigRegistry;
Andrea Campanella59b549d2017-04-14 21:58:16 +020045import org.onosproject.net.config.basics.SubjectFactories;
Andrea Campanella945ded22016-01-07 13:17:43 -080046import org.onosproject.net.device.DefaultDeviceDescription;
47import org.onosproject.net.device.DeviceDescription;
Andrea Campanella6c71a052016-04-22 11:56:31 -070048import org.onosproject.net.device.DeviceDescriptionDiscovery;
Andrea Campanella945ded22016-01-07 13:17:43 -080049import org.onosproject.net.device.DeviceProvider;
50import org.onosproject.net.device.DeviceProviderRegistry;
51import org.onosproject.net.device.DeviceProviderService;
Andrea Campanella6c71a052016-04-22 11:56:31 -070052import org.onosproject.net.device.DeviceService;
Michal Machd8099742017-06-19 14:32:35 +020053import org.onosproject.net.device.PortStatistics;
54import org.onosproject.net.device.PortStatisticsDiscovery;
Michele Santuaric372c222017-01-12 09:41:25 +010055import org.onosproject.net.driver.DefaultDriverData;
56import org.onosproject.net.driver.DefaultDriverHandler;
57import org.onosproject.net.driver.Driver;
58import org.onosproject.net.driver.DriverData;
59import org.onosproject.net.driver.DriverHandler;
60import org.onosproject.net.driver.DriverService;
Andrea Campanella945ded22016-01-07 13:17:43 -080061import org.onosproject.net.provider.AbstractProvider;
62import org.onosproject.net.provider.ProviderId;
Andrea Campanella59b549d2017-04-14 21:58:16 +020063import org.onosproject.protocol.rest.DefaultRestSBDevice;
Andrea Campanella945ded22016-01-07 13:17:43 -080064import org.onosproject.protocol.rest.RestSBController;
65import org.onosproject.protocol.rest.RestSBDevice;
66import org.slf4j.Logger;
67
Andrea Campanellac6ecc632016-03-10 17:57:06 -080068import javax.ws.rs.ProcessingException;
Michal Mach67acb692017-06-21 12:05:36 +020069import javax.ws.rs.core.MediaType;
Michal Machd8099742017-06-19 14:32:35 +020070import java.util.Collection;
Andrea Campanella945ded22016-01-07 13:17:43 -080071import java.util.HashSet;
Andrea Campanella59b549d2017-04-14 21:58:16 +020072import java.util.List;
Andrea Campanella945ded22016-01-07 13:17:43 -080073import java.util.Set;
Palash Kala4c71ee72017-05-24 17:43:59 +090074import java.util.concurrent.Callable;
fahadnaeemkhan02ffa712017-12-01 19:49:45 -080075import java.util.concurrent.CompletableFuture;
Palash Kala4c71ee72017-05-24 17:43:59 +090076import java.util.concurrent.ExecutionException;
Andrea Campanella784ee0f2016-02-17 15:50:59 -080077import java.util.concurrent.ExecutorService;
78import java.util.concurrent.Executors;
Palash Kala4c71ee72017-05-24 17:43:59 +090079import java.util.concurrent.Future;
Michal Machd8099742017-06-19 14:32:35 +020080import java.util.concurrent.ScheduledFuture;
Palash Kala4c71ee72017-05-24 17:43:59 +090081import java.util.concurrent.TimeUnit;
82import java.util.concurrent.TimeoutException;
Andrea Campanella59b549d2017-04-14 21:58:16 +020083import java.util.stream.Collectors;
Andrea Campanella945ded22016-01-07 13:17:43 -080084
Michele Santuaric372c222017-01-12 09:41:25 +010085import static com.google.common.base.Preconditions.checkNotNull;
Andrea Campanella784ee0f2016-02-17 15:50:59 -080086import static org.onlab.util.Tools.groupedThreads;
Andrea Campanella945ded22016-01-07 13:17:43 -080087import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_ADDED;
Yuta HIGUCHIfc667052017-12-05 18:17:22 -080088import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_REMOVED;
Andrea Campanella945ded22016-01-07 13:17:43 -080089import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UPDATED;
Andrea Campanella945ded22016-01-07 13:17:43 -080090import static org.slf4j.LoggerFactory.getLogger;
91
92/**
93 * Provider for devices that use REST as means of configuration communication.
94 */
95@Component(immediate = true)
96public class RestDeviceProvider extends AbstractProvider
97 implements DeviceProvider {
98 private static final String APP_NAME = "org.onosproject.restsb";
Andrea Campanella59b549d2017-04-14 21:58:16 +020099 protected static final String REST = "rest";
Andrea Campanella945ded22016-01-07 13:17:43 -0800100 private static final String PROVIDER = "org.onosproject.provider.rest.device";
101 private static final String IPADDRESS = "ipaddress";
Michal Mach67acb692017-06-21 12:05:36 +0200102 private static final String ISNOTNULL = "Rest device is not null";
Michele Santuaric372c222017-01-12 09:41:25 +0100103 private static final String UNKNOWN = "unknown";
Palash Kala4c71ee72017-05-24 17:43:59 +0900104 private static final int REST_TIMEOUT_SEC = 5;
Michal Machd8099742017-06-19 14:32:35 +0200105 private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 30;
Georgios Katsikas6a4d1662017-07-27 13:22:31 +0200106 private static final int EXECUTOR_THREAD_POOL_SIZE = 8;
Andrea Campanella945ded22016-01-07 13:17:43 -0800107 private final Logger log = getLogger(getClass());
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected DeviceProviderRegistry providerRegistry;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected RestSBController controller;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected NetworkConfigRegistry cfgService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected CoreService coreService;
120
Andrea Campanellad8d92db2016-01-14 16:24:41 -0800121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanella6c71a052016-04-22 11:56:31 -0700122 protected DeviceService deviceService;
Andrea Campanellad8d92db2016-01-14 16:24:41 -0800123
Michele Santuaric372c222017-01-12 09:41:25 +0100124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected DriverService driverService;
126
Andrea Campanella945ded22016-01-07 13:17:43 -0800127 private DeviceProviderService providerService;
Michele Santuaric372c222017-01-12 09:41:25 +0100128 private ApplicationId appId;
Andrea Campanella945ded22016-01-07 13:17:43 -0800129
Michal Mach13072e22017-06-21 09:12:24 +0200130 private ExecutorService executor;
Michal Mach67acb692017-06-21 12:05:36 +0200131 private final SharedScheduledExecutorService portStatisticsExecutor =
132 SharedScheduledExecutors.getPoolThreadExecutor();
Andrea Campanella784ee0f2016-02-17 15:50:59 -0800133
Michal Mach67acb692017-06-21 12:05:36 +0200134 private final List<ConfigFactory> factories = ImmutableList.of(
Andrea Campanella59b549d2017-04-14 21:58:16 +0200135 new ConfigFactory<DeviceId, RestDeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
136 RestDeviceConfig.class,
137 REST) {
138 @Override
139 public RestDeviceConfig createConfig() {
140 return new RestDeviceConfig();
141 }
142 });
143
Michal Mach67acb692017-06-21 12:05:36 +0200144 private final NetworkConfigListener configListener = new InternalNetworkConfigListener();
Andrea Campanella945ded22016-01-07 13:17:43 -0800145
Michal Machd8099742017-06-19 14:32:35 +0200146 private ScheduledFuture<?> scheduledTask;
Andrea Campanella784ee0f2016-02-17 15:50:59 -0800147
Andrea Campanella945ded22016-01-07 13:17:43 -0800148
149 @Activate
150 public void activate() {
151 appId = coreService.registerApplication(APP_NAME);
152 providerService = providerRegistry.register(this);
Andrea Campanella59b549d2017-04-14 21:58:16 +0200153 factories.forEach(cfgService::registerConfigFactory);
Georgios Katsikas6a4d1662017-07-27 13:22:31 +0200154 executor = Executors.newFixedThreadPool(
155 EXECUTOR_THREAD_POOL_SIZE, groupedThreads("onos/restsbprovider", "device-installer-%d", log)
156 );
Michal Mach67acb692017-06-21 12:05:36 +0200157 cfgService.addListener(configListener);
Andrea Campanella59b549d2017-04-14 21:58:16 +0200158 executor.execute(RestDeviceProvider.this::createAndConnectDevices);
Michal Machd8099742017-06-19 14:32:35 +0200159 scheduledTask = schedulePolling();
Andrea Campanella945ded22016-01-07 13:17:43 -0800160 log.info("Started");
161 }
162
Andrea Campanella945ded22016-01-07 13:17:43 -0800163 @Deactivate
164 public void deactivate() {
Michal Mach67acb692017-06-21 12:05:36 +0200165 cfgService.removeListener(configListener);
Andrea Campanella945ded22016-01-07 13:17:43 -0800166 providerRegistry.unregister(this);
167 providerService = null;
Andrea Campanella59b549d2017-04-14 21:58:16 +0200168 factories.forEach(cfgService::unregisterConfigFactory);
Michal Machd8099742017-06-19 14:32:35 +0200169 scheduledTask.cancel(true);
Lukasz Ryba4da35c52017-06-20 09:14:11 +0200170 executor.shutdown();
Andrea Campanella945ded22016-01-07 13:17:43 -0800171 log.info("Stopped");
172 }
173
174 public RestDeviceProvider() {
175 super(new ProviderId(REST, PROVIDER));
176 }
177
178 @Override
179 public void triggerProbe(DeviceId deviceId) {
180 // TODO: This will be implemented later.
181 log.info("Triggering probe on device {}", deviceId);
182 }
183
184 @Override
185 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
186 // TODO: This will be implemented later.
187 }
188
Andrea Campanella945ded22016-01-07 13:17:43 -0800189 @Override
190 public boolean isReachable(DeviceId deviceId) {
191 RestSBDevice restDevice = controller.getDevice(deviceId);
192 if (restDevice == null) {
Michele Santuaric372c222017-01-12 09:41:25 +0100193 restDevice = controller.getProxySBDevice(deviceId);
194 if (restDevice == null) {
195 log.debug("the requested device id: " +
196 deviceId.toString() +
197 " is not associated to any REST or REST " +
198 "proxy Device");
199 return false;
200 }
Andrea Campanella945ded22016-01-07 13:17:43 -0800201 }
202 return restDevice.isActive();
203 }
204
Michele Santuaric372c222017-01-12 09:41:25 +0100205 private void deviceAdded(RestSBDevice restSBDev) {
206 checkNotNull(restSBDev, ISNOTNULL);
207
208 //check if the server is controlling a single or multiple devices
209 if (restSBDev.isProxy()) {
210
211 Driver driver = driverService.getDriver(restSBDev.manufacturer().get(),
212 restSBDev.hwVersion().get(),
213 restSBDev.swVersion().get());
214
215 if (driver != null && driver.hasBehaviour(DevicesDiscovery.class)) {
216
217 //Creates the driver to communicate with the server
218 DevicesDiscovery devicesDiscovery =
219 devicesDiscovery(restSBDev, driver);
220 Set<DeviceId> deviceIds = devicesDiscovery.deviceIds();
221 restSBDev.setActive(true);
Michal Mach67acb692017-06-21 12:05:36 +0200222 deviceIds.forEach(deviceId -> {
Michele Santuaric372c222017-01-12 09:41:25 +0100223 controller.addProxiedDevice(deviceId, restSBDev);
224 DeviceDescription devDesc =
225 devicesDiscovery.deviceDetails(deviceId);
226 checkNotNull(devDesc,
227 "deviceDescription cannot be null");
228 providerService.deviceConnected(
229 deviceId, mergeAnn(restSBDev.deviceId(), devDesc));
230
231 if (driver.hasBehaviour(DeviceDescriptionDiscovery.class)) {
232 DriverHandler h = driverService.createHandler(deviceId);
233 DeviceDescriptionDiscovery devDisc =
234 h.behaviour(DeviceDescriptionDiscovery.class);
235 providerService.updatePorts(deviceId,
236 devDisc.discoverPortDetails());
237 }
238
239 checkAndUpdateDevice(deviceId);
Michele Santuaric372c222017-01-12 09:41:25 +0100240 });
241 } else {
242 log.warn("Driver not found for {}", restSBDev);
243 }
244 } else {
245 DeviceId deviceId = restSBDev.deviceId();
246 ChassisId cid = new ChassisId();
247 String ipAddress = restSBDev.ip().toString();
248 SparseAnnotations annotations = DefaultAnnotations.builder()
249 .set(IPADDRESS, ipAddress)
250 .set(AnnotationKeys.PROTOCOL, REST.toUpperCase())
251 .build();
252 DeviceDescription deviceDescription = new DefaultDeviceDescription(
253 deviceId.uri(),
254 Device.Type.SWITCH,
255 UNKNOWN, UNKNOWN,
256 UNKNOWN, UNKNOWN,
257 cid,
258 annotations);
259 restSBDev.setActive(true);
260 providerService.deviceConnected(deviceId, deviceDescription);
261 checkAndUpdateDevice(deviceId);
Michele Santuaric372c222017-01-12 09:41:25 +0100262 }
263 }
264
265 private DefaultDeviceDescription mergeAnn(DeviceId devId, DeviceDescription desc) {
266 return new DefaultDeviceDescription(
267 desc,
268 DefaultAnnotations.merge(
269 DefaultAnnotations.builder()
270 .set(AnnotationKeys.PROTOCOL, REST.toUpperCase())
271 // The rest server added as annotation to the device
272 .set(AnnotationKeys.REST_SERVER, devId.toString())
273 .build(),
274 desc.annotations()));
275 }
276
277 private DevicesDiscovery devicesDiscovery(RestSBDevice restSBDevice, Driver driver) {
278 DriverData driverData = new DefaultDriverData(driver, restSBDevice.deviceId());
279 DevicesDiscovery devicesDiscovery = driver.createBehaviour(driverData,
280 DevicesDiscovery.class);
281 devicesDiscovery.setHandler(new DefaultDriverHandler(driverData));
282 return devicesDiscovery;
Andrea Campanella945ded22016-01-07 13:17:43 -0800283 }
284
Konstantinos Kanonakis3cd85552016-11-17 10:11:13 -0600285 private void checkAndUpdateDevice(DeviceId deviceId) {
286 if (deviceService.getDevice(deviceId) == null) {
287 log.warn("Device {} has not been added to store, " +
288 "maybe due to a problem in connectivity", deviceId);
289 } else {
290 boolean isReachable = isReachable(deviceId);
291 if (isReachable && deviceService.isAvailable(deviceId)) {
292 Device device = deviceService.getDevice(deviceId);
293 if (device.is(DeviceDescriptionDiscovery.class)) {
Michele Santuaric372c222017-01-12 09:41:25 +0100294 DeviceDescriptionDiscovery deviceDescriptionDiscovery =
295 device.as(DeviceDescriptionDiscovery.class);
296 DeviceDescription updatedDeviceDescription =
297 deviceDescriptionDiscovery.discoverDeviceDetails();
298 if (updatedDeviceDescription != null &&
299 !descriptionEquals(device, updatedDeviceDescription)) {
300 providerService.deviceConnected(
301 deviceId,
302 new DefaultDeviceDescription(
303 updatedDeviceDescription, true,
304 updatedDeviceDescription.annotations()));
Konstantinos Kanonakis3cd85552016-11-17 10:11:13 -0600305 //if ports are not discovered, retry the discovery
306 if (deviceService.getPorts(deviceId).isEmpty()) {
307 discoverPorts(deviceId);
308 }
309 }
310 } else {
311 log.warn("No DeviceDescriptionDiscovery behaviour for device {}", deviceId);
312 }
313 } else if (!isReachable && deviceService.isAvailable(deviceId)) {
314 providerService.deviceDisconnected(deviceId);
315 }
316 }
317 }
318
319 private boolean descriptionEquals(Device device, DeviceDescription updatedDeviceDescription) {
Michele Santuarid2c8f212017-01-09 18:23:45 +0100320 return Objects.equal(device.id().uri(), updatedDeviceDescription.deviceUri())
Konstantinos Kanonakis3cd85552016-11-17 10:11:13 -0600321 && Objects.equal(device.type(), updatedDeviceDescription.type())
322 && Objects.equal(device.manufacturer(), updatedDeviceDescription.manufacturer())
323 && Objects.equal(device.hwVersion(), updatedDeviceDescription.hwVersion())
324 && Objects.equal(device.swVersion(), updatedDeviceDescription.swVersion())
325 && Objects.equal(device.serialNumber(), updatedDeviceDescription.serialNumber())
326 && Objects.equal(device.chassisId(), updatedDeviceDescription.chassisId())
327 && Objects.equal(device.annotations(), updatedDeviceDescription.annotations());
328 }
329
Andrea Campanella86294db2016-03-07 11:42:49 -0800330 private void deviceRemoved(DeviceId deviceId) {
Michele Santuaric372c222017-01-12 09:41:25 +0100331 checkNotNull(deviceId, ISNOTNULL);
Andrea Campanella945ded22016-01-07 13:17:43 -0800332 providerService.deviceDisconnected(deviceId);
Michal Mach67acb692017-06-21 12:05:36 +0200333 controller.getProxiedDevices(deviceId).forEach(device -> {
Michele Santuaric372c222017-01-12 09:41:25 +0100334 controller.removeProxiedDevice(device);
335 providerService.deviceDisconnected(device);
336 });
Andrea Campanella86294db2016-03-07 11:42:49 -0800337 controller.removeDevice(deviceId);
Andrea Campanella945ded22016-01-07 13:17:43 -0800338 }
339
Andrea Campanella59b549d2017-04-14 21:58:16 +0200340 //Method to connect devices provided via net-cfg under devices/ tree
341 private void createAndConnectDevices() {
342 Set<DeviceId> deviceSubjects =
343 cfgService.getSubjects(DeviceId.class, RestDeviceConfig.class);
344 connectDevices(deviceSubjects.stream()
fahadnaeemkhan02ffa712017-12-01 19:49:45 -0800345 .filter(deviceId -> deviceService.getDevice(deviceId) == null)
346 .map(deviceId -> {
347 RestDeviceConfig config =
348 cfgService.getConfig(deviceId, RestDeviceConfig.class);
Yuta HIGUCHIfc667052017-12-05 18:17:22 -0800349 return toInactiveRestSBDevice(config);
fahadnaeemkhan02ffa712017-12-01 19:49:45 -0800350 }).collect(Collectors.toSet()));
Andrea Campanella59b549d2017-04-14 21:58:16 +0200351 }
352
Yuta HIGUCHIfc667052017-12-05 18:17:22 -0800353 private RestSBDevice toInactiveRestSBDevice(RestDeviceConfig config) {
354 return new DefaultRestSBDevice(config.ip(),
355 config.port(),
356 config.username(),
357 config.password(),
358 config.protocol(),
359 config.url(),
360 false,
361 config.testUrl(),
362 config.manufacturer(),
363 config.hwVersion(),
364 config.swVersion(),
365 config.authenticationScheme(),
366 config.token()
367 );
368 }
369
Andrea Campanella59b549d2017-04-14 21:58:16 +0200370 private void connectDevices(Set<RestSBDevice> devices) {
371 //Precomputing the devices to be removed
372 Set<RestSBDevice> toBeRemoved = new HashSet<>(controller.getDevices().values());
373 toBeRemoved.removeAll(devices);
374 //Adding new devices
375 devices.stream()
376 .filter(device -> {
377 device.setActive(false);
378 controller.addDevice(device);
379 return testDeviceConnection(device);
380 })
Michal Mach67acb692017-06-21 12:05:36 +0200381 .forEach(this::deviceAdded);
Andrea Campanella59b549d2017-04-14 21:58:16 +0200382 //Removing devices not wanted anymore
383 toBeRemoved.forEach(device -> deviceRemoved(device.deviceId()));
384 }
385
Yuta HIGUCHIfc667052017-12-05 18:17:22 -0800386 private void connectDevice(RestSBDevice device) {
387 // TODO borrowed from above,
388 // not sure why setting it to inactive
389 device.setActive(false);
390 controller.addDevice(device);
391 if (testDeviceConnection(device)) {
392 deviceAdded(device);
393 }
394 }
395
Michal Machd8099742017-06-19 14:32:35 +0200396 private ScheduledFuture schedulePolling() {
397 return portStatisticsExecutor.scheduleAtFixedRate(this::executePortStatisticsUpdate,
398 DEFAULT_POLL_FREQUENCY_SECONDS / 2,
399 DEFAULT_POLL_FREQUENCY_SECONDS,
400 TimeUnit.SECONDS);
401 }
402
403 private void executePortStatisticsUpdate() {
404 controller.getDevices().keySet().forEach(this::updatePortStatistics);
405 }
406
407 private void updatePortStatistics(DeviceId deviceId) {
408 Device device = deviceService.getDevice(deviceId);
409 checkNotNull(device, "device cannot be null");
410
411 if (device.is(PortStatisticsDiscovery.class)) {
412 PortStatisticsDiscovery portStatisticsDiscovery = device.as(PortStatisticsDiscovery.class);
413 Collection<PortStatistics> portStatistics = portStatisticsDiscovery.discoverPortStatistics();
414 if (portStatistics != null && !portStatistics.isEmpty()) {
415 providerService.updatePortStatistics(deviceId, portStatistics);
416 }
417 } else {
418 log.debug("No port statistics getter behaviour for device {}", deviceId);
419 }
420 }
421
Andrea Campanella6c71a052016-04-22 11:56:31 -0700422 private void discoverPorts(DeviceId deviceId) {
423 Device device = deviceService.getDevice(deviceId);
Ray Milkey640fedd2018-02-08 09:02:26 -0800424 DeviceDescriptionDiscovery deviceDescriptionDiscovery =
425 device.as(DeviceDescriptionDiscovery.class);
426 providerService.updatePorts(deviceId, deviceDescriptionDiscovery.discoverPortDetails());
Andrea Campanella6c71a052016-04-22 11:56:31 -0700427 }
428
Michele Santuaric372c222017-01-12 09:41:25 +0100429 private boolean testDeviceConnection(RestSBDevice dev) {
Andrea Campanella945ded22016-01-07 13:17:43 -0800430 try {
Palash Kala4c71ee72017-05-24 17:43:59 +0900431 Callable<Boolean> connectionSuccess;
432
Michele Santuaric372c222017-01-12 09:41:25 +0100433 if (dev.testUrl().isPresent()) {
Michal Mach67acb692017-06-21 12:05:36 +0200434 connectionSuccess = () ->
435 controller.get(dev.deviceId(), dev.testUrl().get(), MediaType.APPLICATION_JSON_TYPE) != null;
Palash Kala4c71ee72017-05-24 17:43:59 +0900436 } else {
Michal Mach67acb692017-06-21 12:05:36 +0200437 connectionSuccess = () ->
438 controller.get(dev.deviceId(), "", MediaType.APPLICATION_JSON_TYPE) != null;
Michele Santuaric372c222017-01-12 09:41:25 +0100439 }
Palash Kala4c71ee72017-05-24 17:43:59 +0900440
441 Future<Boolean> future = executor.submit(connectionSuccess);
442 try {
Michal Mach67acb692017-06-21 12:05:36 +0200443 return future.get(REST_TIMEOUT_SEC, TimeUnit.SECONDS);
Palash Kala4c71ee72017-05-24 17:43:59 +0900444 } catch (TimeoutException ex) {
445 log.warn("Connection to device {} timed out", dev.deviceId());
446 return false;
447 } catch (InterruptedException ex) {
448 log.warn("Connection to device {} interrupted", dev.deviceId());
Ray Milkey5c7d4882018-02-05 14:50:39 -0800449 Thread.currentThread().interrupt();
Palash Kala4c71ee72017-05-24 17:43:59 +0900450 return false;
451 } catch (ExecutionException ex) {
452 log.warn("Connection to device {} had a execution exception", dev.deviceId());
453 return false;
454 }
Michele Santuaric372c222017-01-12 09:41:25 +0100455
Andrea Campanellac6ecc632016-03-10 17:57:06 -0800456 } catch (ProcessingException e) {
Michele Santuaric372c222017-01-12 09:41:25 +0100457 log.warn("Cannot connect to device {}", dev, e);
Andrea Campanella945ded22016-01-07 13:17:43 -0800458 }
459 return false;
460 }
461
462 private class InternalNetworkConfigListener implements NetworkConfigListener {
Andrea Campanella945ded22016-01-07 13:17:43 -0800463 @Override
464 public void event(NetworkConfigEvent event) {
Yuta HIGUCHIfc667052017-12-05 18:17:22 -0800465 ExecutorService bg = SharedExecutors.getSingleThreadExecutor();
466 if (event.type() == CONFIG_REMOVED) {
467 DeviceId did = (DeviceId) event.subject();
468 bg.execute(() -> deviceRemoved(did));
469 } else {
470 // CONFIG_ADDED or CONFIG_UPDATED
471 RestDeviceConfig cfg = (RestDeviceConfig) event.config().get();
472 RestSBDevice restSBDevice = toInactiveRestSBDevice(cfg);
473 bg.execute(() -> connectDevice(restSBDevice));
474 }
Andrea Campanella945ded22016-01-07 13:17:43 -0800475 }
476
477 @Override
478 public boolean isRelevant(NetworkConfigEvent event) {
Yuta HIGUCHI872fdbe2017-12-05 15:34:28 -0800479 return event.configClass().equals(RestDeviceConfig.class) &&
Andrea Campanella945ded22016-01-07 13:17:43 -0800480 (event.type() == CONFIG_ADDED ||
Yuta HIGUCHIfc667052017-12-05 18:17:22 -0800481 event.type() == CONFIG_UPDATED ||
482 event.type() == CONFIG_REMOVED);
Andrea Campanella945ded22016-01-07 13:17:43 -0800483 }
484 }
Saurav Dasa2d37502016-03-25 17:50:40 -0700485
486 @Override
487 public void changePortState(DeviceId deviceId, PortNumber portNumber,
488 boolean enable) {
fahadnaeemkhan482951f2017-08-24 16:35:17 -0700489 Device device = deviceService.getDevice(deviceId);
490 if (device != null) {
491 if (device.is(PortAdmin.class)) {
492 PortAdmin portAdmin = device.as(PortAdmin.class);
493 CompletableFuture<Boolean> modified;
494 if (enable) {
495 modified = portAdmin.enable(portNumber);
496 } else {
497 modified = portAdmin.disable(portNumber);
498 }
499 modified.thenAcceptAsync(result -> {
500 if (!result) {
501 log.warn("Device {} port {} state can't be changed to {}",
502 deviceId, portNumber, enable);
503 }
504 });
505
506 } else {
507 log.warn("Device {} does not support PortAdmin behavior", deviceId);
508 }
509 } else {
510 log.warn("unable to get the device {}, port {} state can't be changed to {}",
511 deviceId, portNumber, enable);
512 }
Saurav Dasa2d37502016-03-25 17:50:40 -0700513 }
Andrea Campanella945ded22016-01-07 13:17:43 -0800514}