Enable REST to manage devices under a proxy
This commit integrates the REST proxy within the standard REST
protocol and provider, supporting multiple devices managed by
a single REST end point (e.g. a REST-based second level controller).
It introduces the concept of RestSBServer, that represents
the REST service exposed by a single or a set of devices.
Change-Id: I0b187151848c20bc1fd8c39a33d57a500f667533
diff --git a/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java b/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java
index 48f6a68..93f9ca9 100644
--- a/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java
+++ b/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java
@@ -17,7 +17,6 @@
package org.onosproject.provider.rest.device.impl;
import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -34,6 +33,7 @@
import org.onosproject.net.MastershipRole;
import org.onosproject.net.PortNumber;
import org.onosproject.net.SparseAnnotations;
+import org.onosproject.net.behaviour.DevicesDiscovery;
import org.onosproject.net.behaviour.PortDiscovery;
import org.onosproject.net.config.ConfigFactory;
import org.onosproject.net.config.NetworkConfigEvent;
@@ -46,6 +46,12 @@
import org.onosproject.net.device.DeviceProviderRegistry;
import org.onosproject.net.device.DeviceProviderService;
import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.DefaultDriverData;
+import org.onosproject.net.driver.DefaultDriverHandler;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverData;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.protocol.rest.RestSBController;
@@ -58,6 +64,7 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_ADDED;
import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UPDATED;
@@ -75,11 +82,12 @@
private static final String JSON = "json";
private static final String PROVIDER = "org.onosproject.provider.rest.device";
private static final String IPADDRESS = "ipaddress";
- private static final int TEST_CONNECT_TIMEOUT = 1000;
private static final String HTTPS = "https";
private static final String AUTHORIZATION_PROPERTY = "authorization";
private static final String BASIC_AUTH_PREFIX = "Basic ";
private static final String URL_SEPARATOR = "://";
+ protected static final String ISNOTNULL = "Rest device is not null";
+ private static final String UNKNOWN = "unknown";
private final Logger log = getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -97,10 +105,12 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DriverService driverService;
+
private DeviceProviderService providerService;
- protected static final String ISNOTNULL = "Rest device is not null";
- private static final String UNKNOWN = "unknown";
+ private ApplicationId appId;
private final ExecutorService executor =
Executors.newFixedThreadPool(5, groupedThreads("onos/restsbprovider", "device-installer-%d", log));
@@ -116,7 +126,6 @@
}
};
private final NetworkConfigListener cfgLister = new InternalNetworkConfigListener();
- private ApplicationId appId;
private Set<DeviceId> addedDevices = new HashSet<>();
@@ -161,34 +170,98 @@
public boolean isReachable(DeviceId deviceId) {
RestSBDevice restDevice = controller.getDevice(deviceId);
if (restDevice == null) {
- log.debug("the requested device id: " +
- deviceId.toString() +
- " is not associated to any REST Device");
- return false;
+ restDevice = controller.getProxySBDevice(deviceId);
+ if (restDevice == null) {
+ log.debug("the requested device id: " +
+ deviceId.toString() +
+ " is not associated to any REST or REST " +
+ "proxy Device");
+ return false;
+ }
}
return restDevice.isActive();
}
- private void deviceAdded(RestSBDevice nodeId) {
- Preconditions.checkNotNull(nodeId, ISNOTNULL);
- DeviceId deviceId = nodeId.deviceId();
- ChassisId cid = new ChassisId();
- String ipAddress = nodeId.ip().toString();
- SparseAnnotations annotations = DefaultAnnotations.builder()
- .set(IPADDRESS, ipAddress)
- .set(AnnotationKeys.PROTOCOL, REST.toUpperCase())
- .build();
- DeviceDescription deviceDescription = new DefaultDeviceDescription(
- deviceId.uri(),
- Device.Type.SWITCH,
- UNKNOWN, UNKNOWN,
- UNKNOWN, UNKNOWN,
- cid,
- annotations);
- nodeId.setActive(true);
- providerService.deviceConnected(deviceId, deviceDescription);
- checkAndUpdateDevice(deviceId);
- addedDevices.add(deviceId);
+ private void deviceAdded(RestSBDevice restSBDev) {
+ checkNotNull(restSBDev, ISNOTNULL);
+
+ //check if the server is controlling a single or multiple devices
+ if (restSBDev.isProxy()) {
+
+ Driver driver = driverService.getDriver(restSBDev.manufacturer().get(),
+ restSBDev.hwVersion().get(),
+ restSBDev.swVersion().get());
+
+ if (driver != null && driver.hasBehaviour(DevicesDiscovery.class)) {
+
+ //Creates the driver to communicate with the server
+ DevicesDiscovery devicesDiscovery =
+ devicesDiscovery(restSBDev, driver);
+ Set<DeviceId> deviceIds = devicesDiscovery.deviceIds();
+ restSBDev.setActive(true);
+ deviceIds.stream().forEach(deviceId -> {
+ controller.addProxiedDevice(deviceId, restSBDev);
+ DeviceDescription devDesc =
+ devicesDiscovery.deviceDetails(deviceId);
+ checkNotNull(devDesc,
+ "deviceDescription cannot be null");
+ providerService.deviceConnected(
+ deviceId, mergeAnn(restSBDev.deviceId(), devDesc));
+
+ if (driver.hasBehaviour(DeviceDescriptionDiscovery.class)) {
+ DriverHandler h = driverService.createHandler(deviceId);
+ DeviceDescriptionDiscovery devDisc =
+ h.behaviour(DeviceDescriptionDiscovery.class);
+ providerService.updatePorts(deviceId,
+ devDisc.discoverPortDetails());
+ }
+
+ checkAndUpdateDevice(deviceId);
+ addedDevices.add(deviceId);
+ });
+ } else {
+ log.warn("Driver not found for {}", restSBDev);
+ }
+ } else {
+ DeviceId deviceId = restSBDev.deviceId();
+ ChassisId cid = new ChassisId();
+ String ipAddress = restSBDev.ip().toString();
+ SparseAnnotations annotations = DefaultAnnotations.builder()
+ .set(IPADDRESS, ipAddress)
+ .set(AnnotationKeys.PROTOCOL, REST.toUpperCase())
+ .build();
+ DeviceDescription deviceDescription = new DefaultDeviceDescription(
+ deviceId.uri(),
+ Device.Type.SWITCH,
+ UNKNOWN, UNKNOWN,
+ UNKNOWN, UNKNOWN,
+ cid,
+ annotations);
+ restSBDev.setActive(true);
+ providerService.deviceConnected(deviceId, deviceDescription);
+ checkAndUpdateDevice(deviceId);
+ addedDevices.add(deviceId);
+ }
+ }
+
+ private DefaultDeviceDescription mergeAnn(DeviceId devId, DeviceDescription desc) {
+ return new DefaultDeviceDescription(
+ desc,
+ DefaultAnnotations.merge(
+ DefaultAnnotations.builder()
+ .set(AnnotationKeys.PROTOCOL, REST.toUpperCase())
+ // The rest server added as annotation to the device
+ .set(AnnotationKeys.REST_SERVER, devId.toString())
+ .build(),
+ desc.annotations()));
+ }
+
+ private DevicesDiscovery devicesDiscovery(RestSBDevice restSBDevice, Driver driver) {
+ DriverData driverData = new DefaultDriverData(driver, restSBDevice.deviceId());
+ DevicesDiscovery devicesDiscovery = driver.createBehaviour(driverData,
+ DevicesDiscovery.class);
+ devicesDiscovery.setHandler(new DefaultDriverHandler(driverData));
+ return devicesDiscovery;
}
private void checkAndUpdateDevice(DeviceId deviceId) {
@@ -200,17 +273,17 @@
if (isReachable && deviceService.isAvailable(deviceId)) {
Device device = deviceService.getDevice(deviceId);
if (device.is(DeviceDescriptionDiscovery.class)) {
- DeviceDescriptionDiscovery deviceDescriptionDiscovery =
- device.as(DeviceDescriptionDiscovery.class);
- DeviceDescription updatedDeviceDescription =
- deviceDescriptionDiscovery.discoverDeviceDetails();
- if (updatedDeviceDescription != null &&
- !descriptionEquals(device, updatedDeviceDescription)) {
- providerService.deviceConnected(
- deviceId,
- new DefaultDeviceDescription(
- updatedDeviceDescription, true,
- updatedDeviceDescription.annotations()));
+ DeviceDescriptionDiscovery deviceDescriptionDiscovery =
+ device.as(DeviceDescriptionDiscovery.class);
+ DeviceDescription updatedDeviceDescription =
+ deviceDescriptionDiscovery.discoverDeviceDetails();
+ if (updatedDeviceDescription != null &&
+ !descriptionEquals(device, updatedDeviceDescription)) {
+ providerService.deviceConnected(
+ deviceId,
+ new DefaultDeviceDescription(
+ updatedDeviceDescription, true,
+ updatedDeviceDescription.annotations()));
//if ports are not discovered, retry the discovery
if (deviceService.getPorts(deviceId).isEmpty()) {
discoverPorts(deviceId);
@@ -237,8 +310,12 @@
}
private void deviceRemoved(DeviceId deviceId) {
- Preconditions.checkNotNull(deviceId, ISNOTNULL);
+ checkNotNull(deviceId, ISNOTNULL);
providerService.deviceDisconnected(deviceId);
+ controller.getProxiedDevices(deviceId).stream().forEach(device -> {
+ controller.removeProxiedDevice(device);
+ providerService.deviceDisconnected(device);
+ });
controller.removeDevice(deviceId);
}
@@ -282,11 +359,16 @@
}
}
- private boolean testDeviceConnection(RestSBDevice device) {
+ private boolean testDeviceConnection(RestSBDevice dev) {
try {
- return controller.get(device.deviceId(), "", JSON) != null;
+ if (dev.testUrl().isPresent()) {
+ return controller
+ .get(dev.deviceId(), dev.testUrl().get(), JSON) != null;
+ }
+ return controller.get(dev.deviceId(), "", JSON) != null;
+
} catch (ProcessingException e) {
- log.warn("Cannot connect to device {}", device, e);
+ log.warn("Cannot connect to device {}", dev, e);
}
return false;
}
diff --git a/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProviderUtilities.java b/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProviderUtilities.java
index 1f97bee..e92d941 100644
--- a/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProviderUtilities.java
+++ b/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProviderUtilities.java
@@ -43,7 +43,7 @@
* Needs addressing for secutirty purposes.
*
* @throws NoSuchAlgorithmException if algorithm specified is not available
- * @throws KeyManagementException if unable to use the key
+ * @throws KeyManagementException if unable to use the key
*/
//FIXME redo for security purposes.
protected static void enableSslCert() throws NoSuchAlgorithmException, KeyManagementException {
diff --git a/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestProviderConfig.java b/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestProviderConfig.java
index c31f604..5e6fc96 100644
--- a/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestProviderConfig.java
+++ b/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestProviderConfig.java
@@ -26,7 +26,6 @@
import org.onosproject.protocol.rest.DefaultRestSBDevice;
import org.onosproject.protocol.rest.RestSBDevice;
-
import java.util.Set;
/**
@@ -43,6 +42,10 @@
private static final String PASSWORD = "password";
private static final String PROTOCOL = "protocol";
private static final String URL = "url";
+ private static final String TESTURL = "testUrl";
+ private static final String MANUFACTURER = "manufacturer";
+ private static final String HWVERSION = "hwVersion";
+ private static final String SWVERSION = "swVersion";
public Set<RestSBDevice> getDevicesAddresses() throws ConfigException {
Set<RestSBDevice> devicesAddresses = Sets.newHashSet();
@@ -56,10 +59,15 @@
String password = node.path(PASSWORD).asText();
String protocol = node.path(PROTOCOL).asText();
String url = node.path(URL).asText();
+ String testUrl = node.path(TESTURL).asText();
+ String manufacturer = node.path(MANUFACTURER).asText();
+ String hwVersion = node.path(HWVERSION).asText();
+ String swVersion = node.path(SWVERSION).asText();
+
devicesAddresses.add(new DefaultRestSBDevice(ipAddr, port, username,
password, protocol,
- url, false));
-
+ url, false, testUrl, manufacturer,
+ hwVersion, swVersion));
}
} catch (IllegalArgumentException e) {
throw new ConfigException(CONFIG_VALUE_ERROR, e);