Andrea Campanella
Committed by Gerrit Code Review

ONOS-3692 Southbound Rest provider and protocol

Change-Id: I74a5752d4fce1df88828fa6c531979ab7c30a26a
t
......@@ -128,6 +128,8 @@
<behaviour api="org.onosproject.net.behaviour.Pipeliner"
impl="org.onosproject.driver.pipeline.OltPipeline"/>
</driver>
<driver name="rest" manufacturer="" hwVersion="" swVersion="">
</driver>
<!-- The SoftRouter driver is meant to be used by any software/NPU based
~ switch that wishes to implement a simple 2-table router. To use this
~ driver, configure ONOS with the dpid of the device, or extend the
......
......@@ -239,6 +239,11 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${fasterxml.jackson.version}</version>
......
......@@ -37,6 +37,7 @@
<module>pcep</module>
<module>ovsdb</module>
<module>bgp</module>
<module>rest</module>
</modules>
<dependencies>
......
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2016 Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>onos-restsb</artifactId>
<groupId>org.onosproject</groupId>
<version>1.5.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>onos-restsb-api</artifactId>
<packaging>bundle</packaging>
<description>ONOS Rest southbound plugin API</description>
</project>
\ No newline at end of file
/*
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.protocol.rest;
import com.google.common.base.Preconditions;
import org.onlab.packet.IpAddress;
import org.onosproject.net.DeviceId;
import java.util.Objects;
/**
* Default implementation for Rest devices.
*/
public class DefaultRestSBDevice implements RestSBDevice {
private static final String REST = "rest";
private static final String COLON = ":";
private final IpAddress ip;
private final int port;
private final String name;
private final String password;
private boolean isActive;
private String protocol;
public DefaultRestSBDevice(IpAddress ip, int port, String name, String password,
String protocol, boolean isActive) {
Preconditions.checkNotNull(ip, "IP address cannot be null");
Preconditions.checkArgument(port > 0, "Port address cannot be negative");
Preconditions.checkNotNull(protocol, "protocol address cannot be null");
this.ip = ip;
this.port = port;
this.name = name;
this.password = password;
this.isActive = isActive;
this.protocol = protocol;
}
@Override
public IpAddress ip() {
return ip;
}
@Override
public int port() {
return port;
}
@Override
public String name() {
return name;
}
@Override
public String password() {
return password;
}
@Override
public DeviceId deviceId() {
return DeviceId.deviceId(REST + COLON + ip + COLON + port);
}
@Override
public void setActive(boolean active) {
isActive = active;
}
@Override
public boolean isActive() {
return isActive;
}
@Override
public String protocol() {
return protocol;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof RestSBDevice)) {
return false;
}
RestSBDevice device = (RestSBDevice) obj;
return this.name.equals(device.name()) && this.ip.equals(device.ip()) &&
this.port == device.port();
}
@Override
public int hashCode() {
return Objects.hash(ip, port);
}
}
/*
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.protocol.rest;
import org.onlab.packet.IpAddress;
import org.onosproject.net.DeviceId;
import java.io.InputStream;
import java.util.Map;
/**
* Abstraction of an REST controller. Serves as a one stop shop for obtaining
* Rest southbound devices and (un)register listeners.
*/
public interface RestSBController {
/**
* Returns all the devices known to this controller.
*
* @return map of devices
*/
Map<DeviceId, RestSBDevice> getDevices();
/**
* Returns a device by node identifier.
*
* @param deviceInfo node identifier
* @return RestSBDevice rest device
*/
RestSBDevice getDevice(DeviceId deviceInfo);
/**
* Returns a device by Ip and Port.
*
* @param ip device ip
* @param port device port
* @return RestSBDevice rest device
*/
RestSBDevice getDevice(IpAddress ip, int port);
/**
* Adds a device to the device map.
*
* @param device to be added
*/
void addDevice(RestSBDevice device);
/**
* Removes the device from the devices map.
*
* @param device to be removed
*/
void removeDevice(RestSBDevice device);
/**
* Does a REST POST request with specified parameters to the device.
*
* @param device device to make the request to
* @param request url of the request
* @param payload payload of the request as an InputStream
* @param mediaType type of content in the payload i.e. application/json
* @return true if operation returned 200, 201, 202, false otherwise
*/
boolean post(DeviceId device, String request, InputStream payload, String mediaType);
/**
* Does a REST PUT request with specified parameters to the device.
*
* @param device device to make the request to
* @param request resource path of the request
* @param payload payload of the request as an InputStream
* @param mediaType type of content in the payload i.e. application/json
* @return true if operation returned 200, 201, 202, false otherwise
*/
boolean put(DeviceId device, String request, InputStream payload, String mediaType);
/**
* Does a REST GET request with specified parameters to the device.
*
* @param device device to make the request to
* @param request url of the request
* @param mediaType format to retrieve the content in
* @return an inputstream of data from the reply.
*/
InputStream get(DeviceId device, String request, String mediaType);
/**
* Does a REST DELETE request with specified parameters to the device.
*
* @param device device to make the request to
* @param request url of the request
* @param payload payload of the request as an InputStream
* @param mediaType type of content in the payload i.e. application/json
* @return true if operation returned 200 false otherwise
*/
boolean delete(DeviceId device, String request, InputStream payload, String mediaType);
}
/*
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.protocol.rest;
import org.onlab.packet.IpAddress;
import org.onosproject.net.DeviceId;
/**
* Represents an abstraction of a Rest Device in ONOS.
*/
public interface RestSBDevice {
/**
* Returns the ip of this device.
*
* @return ip
*/
IpAddress ip();
/**
* Returns the password of this device.
*
* @return port
*/
int port();
/**
* Returns the name of this device.
*
* @return name
*/
String name();
/**
* Returns the password of this device.
*
* @return password
*/
String password();
/**
* Returns the ONOS deviceID for this device.
*
* @return DeviceId
*/
DeviceId deviceId();
/**
* Sets or unsets the state of the device.
*
* @param active boolean
*/
void setActive(boolean active);
/**
* Returns the state of this device.
*
* @return state
*/
boolean isActive();
/**
* Returns the protocol for the REST request, usually HTTP o HTTPS.
*
* @return protocol
*/
String protocol();
}
/*
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* REST southbound protocols libraries.
*/
package org.onosproject.protocol.rest;
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2016 Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>onos-restsb</artifactId>
<groupId>org.onosproject</groupId>
<version>1.5.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>onos-restsb-ctl</artifactId>
<packaging>bundle</packaging>
<dependencies>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-restsb-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.protocol.rest.ctl;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import org.apache.commons.io.IOUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.IpAddress;
import org.onosproject.net.DeviceId;
import org.onosproject.protocol.rest.RestSBController;
import org.onosproject.protocol.rest.RestSBDevice;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* The implementation of RestSBController.
*/
@Component(immediate = true)
@Service
public class RestSBControllerImpl implements RestSBController {
private static final Logger log =
LoggerFactory.getLogger(RestSBControllerImpl.class);
private static final String APPLICATION = "application/";
private static final String XML = "xml";
private static final String JSON = "json";
private static final String DOUBLESLASH = "//";
private static final String COLON = ":";
private static final int STATUS_OK = Response.Status.OK.getStatusCode();
private static final int STATUS_CREATED = Response.Status.CREATED.getStatusCode();
private static final int STATUS_ACCEPTED = Response.Status.ACCEPTED.getStatusCode();
private static final String SLASH = "/";
private final Map<DeviceId, RestSBDevice> deviceMap = new ConcurrentHashMap<>();
Client client;
@Activate
public void activate(ComponentContext context) {
client = Client.create();
log.info("Started");
}
@Deactivate
public void deactivate() {
deviceMap.clear();
log.info("Stopped");
}
@Override
public Map<DeviceId, RestSBDevice> getDevices() {
return deviceMap;
}
@Override
public RestSBDevice getDevice(DeviceId deviceInfo) {
return deviceMap.get(deviceInfo);
}
@Override
public RestSBDevice getDevice(IpAddress ip, int port) {
for (DeviceId info : deviceMap.keySet()) {
if (IpAddress.valueOf(info.uri().getHost()).equals(ip) &&
info.uri().getPort() == port) {
return deviceMap.get(info);
}
}
return null;
}
@Override
public void addDevice(RestSBDevice device) {
deviceMap.put(device.deviceId(), device);
}
@Override
public void removeDevice(RestSBDevice device) {
deviceMap.remove(device.deviceId());
}
@Override
public boolean post(DeviceId device, String request, InputStream payload, String mediaType) {
WebResource webResource = getWebResource(device, request);
ClientResponse response = null;
if (payload != null) {
try {
response = webResource.accept(mediaType)
.post(ClientResponse.class, IOUtils.toString(payload, StandardCharsets.UTF_8));
} catch (IOException e) {
log.error("Cannot do POST {} request on device {} because can't read payload",
request, device);
}
} else {
response = webResource.accept(mediaType)
.post(ClientResponse.class);
}
return checkReply(response);
}
@Override
public boolean put(DeviceId device, String request, InputStream payload, String mediaType) {
WebResource webResource = getWebResource(device, request);
ClientResponse response = null;
if (payload != null) {
try {
response = webResource.accept(mediaType)
.put(ClientResponse.class, IOUtils.toString(payload, StandardCharsets.UTF_8));
} catch (IOException e) {
log.error("Cannot do PUT {} request on device {} because can't read payload",
request, device);
}
} else {
response = webResource.accept(mediaType)
.put(ClientResponse.class);
}
return checkReply(response);
}
@Override
public InputStream get(DeviceId device, String request, String mediaType) {
WebResource webResource = getWebResource(device, request);
String type;
switch (mediaType) {
case XML:
type = MediaType.APPLICATION_XML;
break;
case JSON:
type = MediaType.APPLICATION_JSON;
break;
default:
throw new IllegalArgumentException("Unsupported media type " + mediaType);
}
return new ByteArrayInputStream(webResource.accept(type).get(ClientResponse.class)
.getEntity(String.class)
.getBytes(StandardCharsets.UTF_8));
}
@Override
public boolean delete(DeviceId device, String request, InputStream payload, String mediaType) {
WebResource webResource = getWebResource(device, request);
ClientResponse response = null;
if (payload != null) {
try {
response = webResource.accept(mediaType)
.delete(ClientResponse.class, IOUtils.toString(payload, StandardCharsets.UTF_8));
} catch (IOException e) {
log.error("Cannot do PUT {} request on device {} because can't read payload",
request, device);
}
} else {
response = webResource.accept(mediaType)
.delete(ClientResponse.class);
}
return checkReply(response);
}
private WebResource getWebResource(DeviceId device, String request) {
return Client.create().resource(deviceMap.get(device).protocol() + COLON +
DOUBLESLASH +
deviceMap.get(device).ip().toString() +
COLON + deviceMap.get(device).port() +
SLASH + request);
}
private boolean checkReply(ClientResponse response) {
if (response != null) {
if (response.getStatus() == STATUS_OK ||
response.getStatus() == STATUS_CREATED ||
response.getStatus() == STATUS_ACCEPTED) {
return true;
} else {
log.error("Failed request: HTTP error code : "
+ response.getStatus());
return false;
}
}
log.error("Null reply from device");
return false;
}
}
/*
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* NETCONF libraries.
*/
package org.onosproject.protocol.rest.ctl;
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2016 Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>onos-protocols</artifactId>
<groupId>org.onosproject</groupId>
<version>1.5.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>onos-restsb</artifactId>
<packaging>pom</packaging>
<modules>
<module>api</module>
<module>ctl</module>
</modules>
<dependencies>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
......@@ -38,6 +38,7 @@
<version>${project.version}</version>
</dependency>
<!-- Add other dependencies here as more bundles are added to the app -->
</dependencies>
</project>
......
......@@ -42,6 +42,7 @@
<module>ovsdb</module>
<module>bgp</module>
<module>snmp</module>
<module>rest</module>
</modules>
<dependencies>
......
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2016 Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<app name="org.onosproject.restsb" origin="ON.Lab" version="${project.version}"
featuresRepo="mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features"
features="${project.artifactId}">
<description>${project.description}</description>
<artifact>mvn:${project.groupId}/onos-restsb-api/${project.version}</artifact>
<artifact>mvn:${project.groupId}/onos-restsb-ctl/${project.version}</artifact>
<artifact>mvn:${project.groupId}/onos-drivers/${project.version}</artifact>
<artifact>mvn:${project.groupId}/onos-restsb-provider-device/${project.version}</artifact>
</app>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
~ Copyright 2016 Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
<feature name="${project.artifactId}" version="${project.version}"
description="${project.description}">
<feature>onos-api</feature>
<bundle>mvn:${project.groupId}/onos-restsb-api/${project.version}</bundle>
<bundle>mvn:${project.groupId}/onos-restsb-ctl/${project.version}</bundle>
<bundle>mvn:${project.groupId}/onos-restsb-provider-device/${project.version}</bundle>
<bundle>mvn:com.sun.jersey/jersey-client/1.19</bundle>
<bundle>mvn:commons-io/commons-io/2.4</bundle>
</feature>
</features>
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2016 Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.onosproject</groupId>
<artifactId>onos-restsb-providers</artifactId>
<version>1.5.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>onos-restsb-app</artifactId>
<packaging>pom</packaging>
<description>REST protocol southbound providers</description>
<dependencies>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-restsb-provider-device</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Add other dependencies here as more bundles are added to the app -->
</dependencies>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2016 Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>onos-restsb-providers</artifactId>
<groupId>org.onosproject</groupId>
<version>1.5.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>onos-restsb-provider-device</artifactId>
<packaging>bundle</packaging>
<dependencies>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-restsb-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-restsb-ctl</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.onosproject</groupId>
<artifactId>onos-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
/*
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.provider.rest.device.impl;
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;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.ChassisId;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.incubator.net.config.basics.ConfigException;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.MastershipRole;
import org.onosproject.net.SparseAnnotations;
import org.onosproject.net.config.ConfigFactory;
import org.onosproject.net.config.NetworkConfigEvent;
import org.onosproject.net.config.NetworkConfigListener;
import org.onosproject.net.config.NetworkConfigRegistry;
import org.onosproject.net.device.DefaultDeviceDescription;
import org.onosproject.net.device.DeviceDescription;
import org.onosproject.net.device.DeviceProvider;
import org.onosproject.net.device.DeviceProviderRegistry;
import org.onosproject.net.device.DeviceProviderService;
import org.onosproject.net.device.PortDescription;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.protocol.rest.RestSBController;
import org.onosproject.protocol.rest.RestSBDevice;
import org.slf4j.Logger;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_ADDED;
import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UPDATED;
import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Provider for devices that use REST as means of configuration communication.
*/
@Component(immediate = true)
public class RestDeviceProvider extends AbstractProvider
implements DeviceProvider {
private static final String APP_NAME = "org.onosproject.restsb";
private static final String REST = "rest";
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 final Logger log = getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceProviderRegistry providerRegistry;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected RestSBController controller;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigRegistry cfgService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
private DeviceProviderService providerService;
protected static final String ISNOTNULL = "Rest device is not null";
private static final String UNKNOWN = "unknown";
private final ConfigFactory factory =
new ConfigFactory<ApplicationId, RestProviderConfig>(APP_SUBJECT_FACTORY,
RestProviderConfig.class,
"restDevices",
true) {
@Override
public RestProviderConfig createConfig() {
return new RestProviderConfig();
}
};
private final NetworkConfigListener cfgLister = new InternalNetworkConfigListener();
private ApplicationId appId;
@Activate
public void activate() {
appId = coreService.registerApplication(APP_NAME);
providerService = providerRegistry.register(this);
cfgService.registerConfigFactory(factory);
cfgService.addListener(cfgLister);
connectDevices();
log.info("Started");
}
@Deactivate
public void deactivate() {
providerRegistry.unregister(this);
providerService = null;
cfgService.unregisterConfigFactory(factory);
cfgService.removeListener(cfgLister);
log.info("Stopped");
}
public RestDeviceProvider() {
super(new ProviderId(REST, PROVIDER));
}
@Override
public void triggerProbe(DeviceId deviceId) {
// TODO: This will be implemented later.
log.info("Triggering probe on device {}", deviceId);
}
@Override
public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
// TODO: This will be implemented later.
}
@Override
public boolean isReachable(DeviceId deviceId) {
RestSBDevice restDevice = controller.getDevice(deviceId);
if (restDevice == null) {
log.warn("BAD REQUEST: the requested device id: " +
deviceId.toString() +
" is not associated to any REST 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).build();
DeviceDescription deviceDescription = new DefaultDeviceDescription(
deviceId.uri(),
Device.Type.SWITCH,
UNKNOWN, UNKNOWN,
UNKNOWN, UNKNOWN,
cid,
annotations);
providerService.deviceConnected(deviceId, deviceDescription);
nodeId.setActive(true);
controller.addDevice(nodeId);
}
private void updatePorts(DeviceId deviceId, List<PortDescription> portDescriptions) {
// TODO get driver and call behavior to get ports
//signal the ports to onos
}
//when do I call it ?
public void deviceRemoved(RestSBDevice nodeId) {
Preconditions.checkNotNull(nodeId, ISNOTNULL);
DeviceId deviceId = nodeId.deviceId();
providerService.deviceDisconnected(deviceId);
controller.removeDevice(nodeId);
}
private void connectDevices() {
RestProviderConfig cfg = cfgService.getConfig(appId, RestProviderConfig.class);
try {
if (cfg != null && cfg.getDevicesAddresses() != null) {
//Precomputing the devices to be removed
Set<RestSBDevice> toBeRemoved = new HashSet<>(controller.getDevices().values());
toBeRemoved.removeAll(cfg.getDevicesAddresses());
//Adding new devices
cfg.getDevicesAddresses().stream()
.filter(device -> testDeviceConnection(device))
.forEach(device -> {
deviceAdded(device);
});
//Removing devices not wanted anymore
toBeRemoved.stream().forEach(device -> deviceRemoved(device));
}
} catch (ConfigException e) {
log.error("Configuration error {}", e);
}
log.info("REST Devices {}", controller.getDevices());
//TODO ask for ports then call update ports.
}
private boolean testDeviceConnection(RestSBDevice device) {
try {
URL url = new URL(device.protocol(), device.ip().toString(), device.port(), "/");
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
urlConn.setConnectTimeout(TEST_CONNECT_TIMEOUT);
boolean open = urlConn.getResponseCode() == (HttpURLConnection.HTTP_OK);
urlConn.disconnect();
return open;
} catch (IOException e) {
log.error("Device {} not reachable, error creating HTTP connection", device, e);
}
return false;
}
private class InternalNetworkConfigListener implements NetworkConfigListener {
@Override
public void event(NetworkConfigEvent event) {
connectDevices();
}
@Override
public boolean isRelevant(NetworkConfigEvent event) {
//TODO refactor
return event.configClass().equals(RestProviderConfig.class) &&
(event.type() == CONFIG_ADDED ||
event.type() == CONFIG_UPDATED);
}
}
}
/*
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.provider.rest.device.impl;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.annotations.Beta;
import com.google.common.collect.Sets;
import org.onlab.packet.IpAddress;
import org.onosproject.core.ApplicationId;
import org.onosproject.incubator.net.config.basics.ConfigException;
import org.onosproject.net.config.Config;
import org.onosproject.protocol.rest.DefaultRestSBDevice;
import org.onosproject.protocol.rest.RestSBDevice;
import java.util.Set;
/**
* Configuration for RestSB provider.
*/
@Beta
public class RestProviderConfig extends Config<ApplicationId> {
public static final String CONFIG_VALUE_ERROR = "Error parsing config value";
private static final String IP = "ip";
private static final int DEFAULT_HTTP_PORT = 80;
private static final String PORT = "port";
private static final String NAME = "name";
private static final String PASSWORD = "password";
private static final String PROTOCOL = "protocol";
public Set<RestSBDevice> getDevicesAddresses() throws ConfigException {
Set<RestSBDevice> devicesAddresses = Sets.newHashSet();
try {
for (JsonNode node : array) {
String ip = node.path(IP).asText();
IpAddress ipAddr = ip.isEmpty() ? null : IpAddress.valueOf(ip);
int port = node.path(PORT).asInt(DEFAULT_HTTP_PORT);
String name = node.path(NAME).asText();
String password = node.path(PASSWORD).asText();
String protocol = node.path(PROTOCOL).asText();
devicesAddresses.add(new DefaultRestSBDevice(ipAddr, port, name,
password, protocol, false));
}
} catch (IllegalArgumentException e) {
throw new ConfigException(CONFIG_VALUE_ERROR, e);
}
return devicesAddresses;
}
}
/*
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Provider that uses REST calls request as a means of device discovery and setup.
*/
package org.onosproject.provider.rest.device.impl;
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2016 Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>onos-providers</artifactId>
<groupId>org.onosproject</groupId>
<version>1.5.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>onos-restsb-providers</artifactId>
<packaging>pom</packaging>
<modules>
<module>app</module>
<module>device</module>
</modules>
</project>
\ No newline at end of file
{
"devices": {
"rest:127.0.0.1:8080": {
"basic": {
"driver": "rest"
}
}
},
"apps": {
"org.onosproject.restsb": {
"restDevices": [{
"name": "local",
"password": "local",
"ip": "127.0.0.1",
"port": 8080,
"protocol": "http"
}]
}
}
}
\ No newline at end of file