Sanjay S
Committed by Gerrit Code Review

Netconf Device Provider Plugin to discover and monitor NETCONF supported Devices.

Change-Id: I6d32c966fd4e9c3581db8285e2d712b6bffdb65c
...@@ -129,5 +129,11 @@ ...@@ -129,5 +129,11 @@
129 <bundle>mvn:org.onosproject/onos-core-common/@ONOS-VERSION</bundle> 129 <bundle>mvn:org.onosproject/onos-core-common/@ONOS-VERSION</bundle>
130 <bundle>mvn:org.onosproject/onos-core-trivial/@ONOS-VERSION</bundle> 130 <bundle>mvn:org.onosproject/onos-core-trivial/@ONOS-VERSION</bundle>
131 </feature> 131 </feature>
132 +
133 + <feature name="onos-netconf" version="@FEATURE-VERSION"
134 + description="ONOS Netconf providers">
135 + <feature>onos-api</feature>
136 + <bundle>mvn:org.onosproject/onos-netconf-provider-device/@ONOS-VERSION</bundle>
137 + </feature>
132 138
133 </features> 139 </features>
......
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2015 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
18 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
19 + <modelVersion>4.0.0</modelVersion>
20 +
21 + <parent>
22 + <groupId>org.onosproject</groupId>
23 + <artifactId>onos-netconf-providers</artifactId>
24 + <version>1.2.0-SNAPSHOT</version>
25 + <relativePath>../pom.xml</relativePath>
26 + </parent>
27 +
28 + <artifactId>onos-netconf-provider-device</artifactId>
29 + <packaging>bundle</packaging>
30 +
31 + <description>ONOS Netconf protocol device provider</description>
32 + <build>
33 + <plugins>
34 + <plugin>
35 + <groupId>org.apache.maven.plugins</groupId>
36 + <artifactId>maven-shade-plugin</artifactId>
37 + <version>2.3</version>
38 + <configuration>
39 + <filters>
40 + <filter>
41 + <artifact>com.tailf:JNC</artifact>
42 + <includes>
43 + <include>com/tailf/jnc/**</include>
44 + </includes>
45 + </filter>
46 + <filter>
47 + <artifact>ch.ethz.ganymed:ganymed-ssh2</artifact>
48 + <includes>
49 + <include>ch/ethz/ssh2/**</include>
50 + </includes>
51 + </filter>
52 + <filter>
53 + <artifact>org.jdom:jdom2</artifact>
54 + <includes>
55 + <include>org/jdom2/**</include>
56 + </includes>
57 + </filter>
58 + </filters>
59 + </configuration>
60 + <executions>
61 + <execution>
62 + <phase>package</phase>
63 + <goals>
64 + <goal>shade</goal>
65 + </goals>
66 + </execution>
67 + </executions>
68 + </plugin>
69 + <plugin>
70 + <groupId>org.apache.felix</groupId>
71 + <artifactId>maven-scr-plugin</artifactId>
72 + </plugin>
73 + <plugin>
74 + <groupId>org.apache.felix</groupId>
75 + <artifactId>maven-bundle-plugin</artifactId>
76 + <configuration>
77 + <instructions>
78 + <Export-Package>
79 + com.tailf.jnc,
80 + ch.ethz.ssh2,
81 + ch.ethz.ssh2.auth,
82 + ch.ethz.ssh2.channel,
83 + ch.ethz.ssh2.crypto,
84 + ch.ethz.ssh2.crypto.cipher,
85 + ch.ethz.ssh2.crypto.dh,
86 + ch.ethz.ssh2.crypto.digest,
87 + ch.ethz.ssh2.log,
88 + ch.ethz.ssh2.packets,
89 + ch.ethz.ssh2.server,
90 + ch.ethz.ssh2.sftp,
91 + ch.ethz.ssh2.signature,
92 + ch.ethz.ssh2.transport,
93 + ch.ethz.ssh2.util,
94 + org.jdom2,
95 + org.jdom2.input,
96 + org.jdom2.output,
97 + org.jdom2.adapters,
98 + org.jdom2.filter,
99 + org.jdom2.internal,
100 + org.jdom2.located,
101 + org.jdom2.transform,
102 + org.jdom2.util,
103 + org.jdom2.xpath,
104 + org.jdom2.input.sax,
105 + org.jdom2.input.stax,
106 + org.jdom2.output.support,
107 + org.jdom2.xpath.jaxen,
108 + org.jdom2.xpath.util
109 + </Export-Package>
110 + </instructions>
111 + </configuration>
112 + </plugin>
113 + <plugin>
114 + <groupId>org.onosproject</groupId>
115 + <artifactId>onos-maven-plugin</artifactId>
116 + </plugin>
117 + </plugins>
118 + </build>
119 + <dependencies>
120 + <dependency>
121 + <groupId>org.osgi</groupId>
122 + <artifactId>org.osgi.compendium</artifactId>
123 + </dependency>
124 + <dependency>
125 + <groupId>ch.ethz.ganymed</groupId>
126 + <artifactId>ganymed-ssh2</artifactId>
127 + <version>262</version>
128 + </dependency>
129 + <dependency>
130 + <!-- TODO: change this appropriately when the official TailF JNC is available -->
131 + <groupId>org.onosproject</groupId>
132 + <artifactId>jnc</artifactId>
133 + <version>1.0</version>
134 + </dependency>
135 + <dependency>
136 + <groupId>org.jdom</groupId>
137 + <artifactId>jdom2</artifactId>
138 + <version>2.0.5</version>
139 + </dependency>
140 + <dependency>
141 + <groupId>jaxen</groupId>
142 + <artifactId>jaxen</artifactId>
143 + <version>1.1.4</version>
144 + <optional>true</optional>
145 + </dependency>
146 + </dependencies>
147 +</project>
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.netconf.device.impl;
17 +
18 +import static com.google.common.base.Preconditions.checkNotNull;
19 +import static org.onlab.util.Tools.delay;
20 +import static org.slf4j.LoggerFactory.getLogger;
21 +
22 +import java.io.IOException;
23 +import java.io.StringReader;
24 +import java.util.ArrayList;
25 +import java.util.List;
26 +
27 +import org.jdom2.Document;
28 +import org.jdom2.Element;
29 +import org.jdom2.input.SAXBuilder;
30 +import org.jdom2.output.Format;
31 +import org.jdom2.output.XMLOutputter;
32 +import org.slf4j.Logger;
33 +
34 +import com.tailf.jnc.Capabilities;
35 +import com.tailf.jnc.JNCException;
36 +import com.tailf.jnc.SSHConnection;
37 +import com.tailf.jnc.SSHSession;
38 +
39 +/**
40 + * This is a logical representation of actual NETCONF device, carrying all the
41 + * necessary information to connect and execute NETCONF operations.
42 + */
43 +public class NetconfDevice {
44 + private static final Logger log = getLogger(NetconfDevice.class);
45 +
46 + /**
47 + * The Device State is used to determine whether the device is active or
48 + * inactive. This state infomation will help Device Creator to add or delete
49 + * the device from the core.
50 + */
51 + public static enum DeviceState {
52 + /* Used to specify Active state of the device */
53 + ACTIVE,
54 + /* Used to specify In Active state of the device */
55 + INACTIVE,
56 + /* Used to specify In Valid state of the device */
57 + INVALID
58 + }
59 +
60 + private static final int DEFAULT_SSH_PORT = 22;
61 + private static final String XML_CAPABILITY_KEY = "capability";
62 + private static final int EVENTINTERVAL = 2000;
63 + private static final int CONNECTION_CHECK_INTERVAL = 3;
64 + private static final String INPUT_HELLO_XML_MSG = new StringBuilder(
65 + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
66 + .append("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">")
67 + .append("<capabilities><capability>urn:ietf:params:netconf:base:1.0</capability>")
68 + .append("</capabilities></hello>").toString();
69 +
70 + private String sshHost;
71 + private int sshPort = DEFAULT_SSH_PORT;
72 + private String username;
73 + private String password;
74 + private boolean reachable = false;
75 +
76 + private List<String> capabilities = new ArrayList<String>();
77 + private SSHConnection sshConnection = null;
78 +
79 + private DeviceState deviceState = DeviceState.INVALID;
80 +
81 + protected NetconfDevice(String sshHost, int sshPort, String username,
82 + String password) {
83 + this.username = checkNotNull(username,
84 + "Netconf Username Cannot be null");
85 + this.sshHost = checkNotNull(sshHost, "Netconf Device IP cannot be null");
86 + this.sshPort = checkNotNull(sshPort,
87 + "Netconf Device SSH port cannot be null");
88 + this.password = password;
89 + }
90 +
91 + /**
92 + * This will try to connect to NETCONF device and find all the capabilities.
93 + */
94 + public void init() throws Exception {
95 + try {
96 + if (sshConnection == null) {
97 + sshConnection = new SSHConnection(sshHost, sshPort);
98 + sshConnection.authenticateWithPassword(username, password);
99 + }
100 + // Send hello message to retrieve capabilities.
101 + } catch (IOException e) {
102 + NetconfDevice.log
103 + .error("Fatal Error while creating connection to the device: "
104 + + deviceInfo(), e);
105 + throw e;
106 + } catch (JNCException e) {
107 + NetconfDevice.log.error("Failed to connect to the device: "
108 + + deviceInfo(), e);
109 + throw e;
110 + }
111 +
112 + hello();
113 + }
114 +
115 + private void hello() {
116 + SSHSession ssh = null;
117 + try {
118 + ssh = new SSHSession(sshConnection);
119 + String helloRequestXML = INPUT_HELLO_XML_MSG.trim();
120 +
121 + if (NetconfDevice.log.isDebugEnabled()) {
122 + NetconfDevice.log
123 + .debug("++++++++++++++++++++++++++++++++++Sending Hello: "
124 + + sshConnection.getGanymedConnection()
125 + .getHostname()
126 + + "++++++++++++++++++++++++++++++++++");
127 + printPrettyXML(helloRequestXML);
128 + }
129 + ssh.print(helloRequestXML);
130 + // ssh.print(endCharSeq);
131 + ssh.flush();
132 + String xmlResponse = null;
133 + int i = CONNECTION_CHECK_INTERVAL;
134 + while (!ssh.ready() && i > 0) {
135 + delay(EVENTINTERVAL);
136 + i--;
137 + }
138 +
139 + if (ssh.ready()) {
140 + StringBuffer readOne = ssh.readOne();
141 + if (readOne == null) {
142 + NetconfDevice.log
143 + .error("The Hello Contains No Capabilites");
144 + throw new JNCException(
145 + JNCException.SESSION_ERROR,
146 + "server does not support NETCONF base capability: "
147 + + Capabilities.NETCONF_BASE_CAPABILITY);
148 + } else {
149 + xmlResponse = readOne.toString().trim();
150 +
151 + if (NetconfDevice.log.isDebugEnabled()) {
152 + NetconfDevice.log
153 + .debug("++++++++++++++++++++++++++++++++++Reading Capabilities: "
154 + + sshConnection.getGanymedConnection()
155 + .getHostname()
156 + + "++++++++++++++++++++++++++++++++++");
157 +
158 + printPrettyXML(xmlResponse);
159 + }
160 + processCapabilities(xmlResponse);
161 + }
162 + }
163 + reachable = true;
164 + } catch (IOException e) {
165 + NetconfDevice.log
166 + .error("Fatal Error while sending Hello Message to the device: "
167 + + deviceInfo(), e);
168 + } catch (JNCException e) {
169 + NetconfDevice.log
170 + .error("Fatal Error while sending Hello Message to the device: "
171 + + deviceInfo(), e);
172 + } finally {
173 + if (NetconfDevice.log.isDebugEnabled()) {
174 + NetconfDevice.log
175 + .debug("Closing the session after successful execution");
176 + }
177 + ssh.close();
178 + }
179 + }
180 +
181 + private void processCapabilities(String xmlResponse) throws JNCException {
182 + if (xmlResponse.isEmpty()) {
183 + NetconfDevice.log.error("The capability response cannot be empty");
184 + throw new JNCException(
185 + JNCException.SESSION_ERROR,
186 + "server does not support NETCONF base capability: "
187 + + Capabilities.NETCONF_BASE_CAPABILITY);
188 + }
189 + try {
190 + Document doc = new SAXBuilder()
191 + .build(new StringReader(xmlResponse));
192 + Element rootElement = doc.getRootElement();
193 + processCapabilities(rootElement);
194 + } catch (Exception e) {
195 + NetconfDevice.log.error("ERROR while parsing the XML "
196 + + xmlResponse);
197 + }
198 + }
199 +
200 + private void processCapabilities(Element rootElement) {
201 + List<Element> children = rootElement.getChildren();
202 + if (children.isEmpty()) {
203 + return;
204 + }
205 + for (Element child : children) {
206 +
207 + if (child.getName().equals(XML_CAPABILITY_KEY)) {
208 + capabilities.add(child.getValue());
209 + }
210 + if (!child.getChildren().isEmpty()) {
211 + processCapabilities(child);
212 + }
213 + }
214 + }
215 +
216 + private void printPrettyXML(String xmlstring) {
217 + try {
218 + Document doc = new SAXBuilder().build(new StringReader(xmlstring));
219 + XMLOutputter xmOut = new XMLOutputter(Format.getPrettyFormat());
220 + String outputString = xmOut.outputString(doc);
221 + if (NetconfDevice.log.isDebugEnabled()) {
222 + NetconfDevice.log.debug(outputString);
223 + }
224 + } catch (Exception e) {
225 + NetconfDevice.log.error("ERROR while parsing the XML " + xmlstring,
226 + e);
227 +
228 + }
229 + }
230 +
231 + /**
232 + * This would return host IP and host Port, used by this particular Netconf
233 + * Device.
234 + * @return Device Information.
235 + */
236 + public String deviceInfo() {
237 + return new StringBuilder("host: ").append(sshHost).append(". port: ")
238 + .append(sshPort).toString();
239 + }
240 +
241 + /**
242 + * This will terminate the device connection.
243 + */
244 + public void disconnect() {
245 + sshConnection.close();
246 + reachable = false;
247 + }
248 +
249 + /**
250 + * This will list down all the capabilities supported on the device.
251 + * @return Capability list.
252 + */
253 + public List<String> getCapabilities() {
254 + return capabilities;
255 + }
256 +
257 + /**
258 + * This api is intended to know whether the device is connected or not.
259 + * @return true if connected
260 + */
261 + public boolean isReachable() {
262 + return reachable;
263 + }
264 +
265 + /**
266 + * This will return the IP used connect ssh on the device.
267 + * @return Netconf Device IP
268 + */
269 + public String getSshHost() {
270 + return sshHost;
271 + }
272 +
273 + /**
274 + * This will return the SSH Port used connect the device.
275 + * @return SSH Port number
276 + */
277 + public int getSshPort() {
278 + return sshPort;
279 + }
280 +
281 + /**
282 + * The usename used to connect Netconf Device.
283 + * @return Device Username
284 + */
285 + public String getUsername() {
286 + return username;
287 + }
288 +
289 + /**
290 + * Retrieve current state of the device.
291 + * @return Current Device State
292 + */
293 + public DeviceState getDeviceState() {
294 + return deviceState;
295 + }
296 +
297 + /**
298 + * This is set the state information for the device.
299 + * @param deviceState Next Device State
300 + */
301 + public void setDeviceState(DeviceState deviceState) {
302 + this.deviceState = deviceState;
303 + }
304 +
305 + /**
306 + * Check whether the device is in Active state.
307 + * @return true if the device is Active
308 + */
309 + public boolean isActive() {
310 + return deviceState == DeviceState.ACTIVE ? true : false;
311 + }
312 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.provider.netconf.device.impl;
17 +
18 +import static com.google.common.base.Strings.isNullOrEmpty;
19 +import static org.onlab.util.Tools.delay;
20 +import static org.onlab.util.Tools.get;
21 +import static org.onlab.util.Tools.groupedThreads;
22 +import static org.slf4j.LoggerFactory.getLogger;
23 +
24 +import java.net.URI;
25 +import java.net.URISyntaxException;
26 +import java.util.Dictionary;
27 +import java.util.Map;
28 +import java.util.Map.Entry;
29 +import java.util.concurrent.ConcurrentHashMap;
30 +import java.util.concurrent.ExecutorService;
31 +import java.util.concurrent.Executors;
32 +import java.util.concurrent.TimeUnit;
33 +
34 +import org.apache.felix.scr.annotations.Activate;
35 +import org.apache.felix.scr.annotations.Component;
36 +import org.apache.felix.scr.annotations.Deactivate;
37 +import org.apache.felix.scr.annotations.Modified;
38 +import org.apache.felix.scr.annotations.Property;
39 +import org.apache.felix.scr.annotations.Reference;
40 +import org.apache.felix.scr.annotations.ReferenceCardinality;
41 +import org.onlab.packet.ChassisId;
42 +import org.onosproject.cluster.ClusterService;
43 +import org.onosproject.net.Device;
44 +import org.onosproject.net.DeviceId;
45 +import org.onosproject.net.MastershipRole;
46 +import org.onosproject.net.device.DefaultDeviceDescription;
47 +import org.onosproject.net.device.DeviceDescription;
48 +import org.onosproject.net.device.DeviceProvider;
49 +import org.onosproject.net.device.DeviceProviderRegistry;
50 +import org.onosproject.net.device.DeviceProviderService;
51 +import org.onosproject.net.device.DeviceService;
52 +import org.onosproject.net.provider.AbstractProvider;
53 +import org.onosproject.net.provider.ProviderId;
54 +import org.onosproject.provider.netconf.device.impl.NetconfDevice.DeviceState;
55 +import org.osgi.service.component.ComponentContext;
56 +import org.slf4j.Logger;
57 +
58 +/**
59 + * Provider which will try to fetch the details of NETCONF devices from the core
60 + * and run a capability discovery on each of the device.
61 + */
62 +@Component(immediate = true)
63 +public class NetconfDeviceProvider extends AbstractProvider
64 + implements DeviceProvider {
65 +
66 + private static final Logger log = getLogger(NetconfDeviceProvider.class);
67 +
68 + private Map<DeviceId, NetconfDevice> netconfDeviceMap = new ConcurrentHashMap<DeviceId, NetconfDevice>();
69 +
70 + private DeviceProviderService providerService;
71 +
72 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 + protected DeviceProviderRegistry providerRegistry;
74 +
75 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 + protected DeviceService deviceService;
77 +
78 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 + protected ClusterService clusterService;
80 +
81 + private ExecutorService deviceBuilder = Executors
82 + .newFixedThreadPool(1,
83 + groupedThreads("onos/netconf", "device-creator"));
84 +
85 + // Delay between events in ms.
86 + private static final int EVENTINTERVAL = 5;
87 +
88 + private static final String SCHEME = "netconf";
89 +
90 + @Property(name = "devConfigs", value = "", label = "Instance-specific configurations")
91 + private String devConfigs = null;
92 +
93 + @Property(name = "devPasswords", value = "", label = "Instace-specific password")
94 + private String devPasswords = null;
95 +
96 + /**
97 + * Creates a provider with the supplier identifier.
98 + */
99 + public NetconfDeviceProvider() {
100 + super(new ProviderId("netconf", "org.onosproject.provider.netconf"));
101 + }
102 +
103 + @Activate
104 + public void activate(ComponentContext context) {
105 + NetconfDeviceProvider.log.info("Netconf Device Provider Started");
106 + providerService = providerRegistry.register(this);
107 + modified(context);
108 + }
109 +
110 + @Deactivate
111 + public void deactivate(ComponentContext context) {
112 + try {
113 + for (Entry<DeviceId, NetconfDevice> deviceEntry : netconfDeviceMap
114 + .entrySet()) {
115 + deviceBuilder.submit(new DeviceCreator(deviceEntry.getValue(),
116 + false));
117 + }
118 + deviceBuilder.awaitTermination(1000, TimeUnit.MILLISECONDS);
119 + } catch (InterruptedException e) {
120 + NetconfDeviceProvider.log.error("Device builder did not terminate");
121 + }
122 + deviceBuilder.shutdownNow();
123 + netconfDeviceMap.clear();
124 + providerRegistry.unregister(this);
125 + providerService = null;
126 + NetconfDeviceProvider.log.info("Stopped");
127 + }
128 +
129 + @Modified
130 + public void modified(ComponentContext context) {
131 + if (context == null) {
132 + NetconfDeviceProvider.log.info("No configuration file");
133 + return;
134 + }
135 + Dictionary<?, ?> properties = context.getProperties();
136 + String deviceCfgValue = get(properties, "devConfigs");
137 + NetconfDeviceProvider.log
138 + .info("Getting Device configuration from cfg file: "
139 + + deviceCfgValue);
140 + if (!isNullOrEmpty(deviceCfgValue)) {
141 + addOrRemoveDevicesConfig(deviceCfgValue);
142 + } else {
143 + NetconfDeviceProvider.log
144 + .info("Device Configuration value receiviced from the property 'devConfigs': "
145 + + deviceCfgValue + ", is not valid");
146 + }
147 + }
148 +
149 + private void addOrRemoveDevicesConfig(String deviceConfig) {
150 + for (String deviceEntry : deviceConfig.split(",")) {
151 + NetconfDevice device = processDeviceEntry(deviceEntry);
152 + if (device != null) {
153 + NetconfDeviceProvider.log.info("Device Detail: " + "username: "
154 + + device.getUsername() + ", host: "
155 + + device.getSshHost() + ", port: "
156 + + device.getSshPort());
157 + if (device.isActive()) {
158 + deviceBuilder.submit(new DeviceCreator(device, true));
159 + } else {
160 + deviceBuilder.submit(new DeviceCreator(device, false));
161 + }
162 + }
163 + }
164 + }
165 +
166 + private NetconfDevice processDeviceEntry(String deviceEntry) {
167 + if (deviceEntry == null) {
168 + NetconfDeviceProvider.log
169 + .info("No content for Device Entry, so cannot proceed further.");
170 + return null;
171 + }
172 + NetconfDeviceProvider.log
173 + .info("Trying to convert Device Entry String: " + deviceEntry
174 + + " to a Netconf Device Object");
175 + NetconfDevice device = null;
176 + try {
177 + String userInfo = deviceEntry.substring(0, deviceEntry
178 + .lastIndexOf('@'));
179 + String hostInfo = deviceEntry.substring(deviceEntry
180 + .lastIndexOf('@') + 1);
181 + String[] infoSplit = userInfo.split(":");
182 + String username = infoSplit[0];
183 + String password = infoSplit[1];
184 + infoSplit = hostInfo.split(":");
185 + String hostIp = infoSplit[0];
186 + Integer hostPort;
187 + try {
188 + hostPort = Integer.parseInt(infoSplit[1]);
189 + } catch (NumberFormatException nfe) {
190 + NetconfDeviceProvider.log
191 + .error("Bad Configuration Data: Failed to parse host port number string: "
192 + + infoSplit[1]);
193 + throw nfe;
194 + }
195 + String deviceState = infoSplit[2];
196 + if (isNullOrEmpty(username) || isNullOrEmpty(password)
197 + || isNullOrEmpty(hostIp) || hostPort == 0) {
198 + NetconfDeviceProvider.log
199 + .warn("Bad Configuration Data: both user and device information parts of Configuration "
200 + + deviceEntry + " should be non-nullable");
201 + } else {
202 + device = new NetconfDevice(hostIp, hostPort, username, password);
203 + if (!isNullOrEmpty(deviceState)) {
204 + if (deviceState.toUpperCase().equals(DeviceState.ACTIVE
205 + .name())) {
206 + device.setDeviceState(DeviceState.ACTIVE);
207 + } else if (deviceState.toUpperCase()
208 + .equals(DeviceState.INACTIVE.name())) {
209 + device.setDeviceState(DeviceState.ACTIVE);
210 + } else {
211 + NetconfDeviceProvider.log
212 + .warn("Device State Information can not be empty, so marking the state as INVALID");
213 + device.setDeviceState(DeviceState.INVALID);
214 + }
215 + } else {
216 + NetconfDeviceProvider.log
217 + .warn("The device entry do not specify state information, so marking the state as INVALID");
218 + device.setDeviceState(DeviceState.INVALID);
219 + }
220 + }
221 + } catch (ArrayIndexOutOfBoundsException aie) {
222 + NetconfDeviceProvider.log
223 + .error("Error while reading config infromation from the config file: "
224 + + "The user, host and device state infomation should be "
225 + + "in the order 'userInfo@hostInfo:deviceState'"
226 + + deviceEntry, aie);
227 + } catch (Exception e) {
228 + NetconfDeviceProvider.log
229 + .error("Error while parsing config information for the device entry: "
230 + + deviceEntry, e);
231 + }
232 + return device;
233 + }
234 +
235 + @Override
236 + public void triggerProbe(DeviceId deviceId) {
237 + // TODO Auto-generated method stub
238 + }
239 +
240 + @Override
241 + public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
242 +
243 + }
244 +
245 + @Override
246 + public boolean isReachable(DeviceId deviceId) {
247 + NetconfDevice netconfDevice = netconfDeviceMap.get(deviceId);
248 + if (netconfDevice == null) {
249 + NetconfDeviceProvider.log
250 + .warn("BAD REQUEST: the requested device id: "
251 + + deviceId.toString()
252 + + " is not associated to any NETCONF Device");
253 + return false;
254 + }
255 + return netconfDevice.isReachable();
256 + }
257 +
258 + /**
259 + * This class is intended to add or remove Configured Netconf Devices.
260 + * Functionality relies on 'createFlag' and 'NetconfDevice' content. The
261 + * functionality runs as a thread and dependening on the 'createFlag' value
262 + * it will create or remove Device entry from the core.
263 + */
264 + private class DeviceCreator implements Runnable {
265 +
266 + private NetconfDevice device;
267 + private boolean createFlag;
268 +
269 + public DeviceCreator(NetconfDevice device, boolean createFlag) {
270 + this.device = device;
271 + this.createFlag = createFlag;
272 + }
273 +
274 + @Override
275 + public void run() {
276 + if (createFlag && (device.getDeviceState() == DeviceState.ACTIVE)) {
277 + NetconfDeviceProvider.log
278 + .info("Trying to create Device Info on ONOS core");
279 + advertiseDevices();
280 + } else {
281 + NetconfDeviceProvider.log
282 + .info("Trying to remove Device Info on ONOS core");
283 + removeDevices();
284 + }
285 + }
286 +
287 + /**
288 + * For each Netconf Device, remove the entry from the device store.
289 + */
290 + private void removeDevices() {
291 + if (!device.isReachable()) {
292 + log.error("BAD Request: 'Currently device is not discovered, so cannot remove/disconnect the device: "
293 + + device.deviceInfo() + "'");
294 + return;
295 + }
296 + try {
297 + DeviceId did = getDeviceId();
298 + providerService.deviceDisconnected(did);
299 + device.disconnect();
300 + delay(EVENTINTERVAL);
301 + } catch (URISyntaxException uriSyntaxExcpetion) {
302 + NetconfDeviceProvider.log
303 + .error("Syntax Error while creating URI for the device: "
304 + + device.deviceInfo()
305 + + " couldn't remove the device from the store",
306 + uriSyntaxExcpetion);
307 + }
308 + }
309 +
310 + /**
311 + * Initialize Netconf Device object, and notify core saying device
312 + * connected.
313 + */
314 + private void advertiseDevices() {
315 + try {
316 + if (device == null) {
317 + NetconfDeviceProvider.log
318 + .warn("The Request Netconf Device is null, cannot proceed further");
319 + return;
320 + }
321 + device.init();
322 + DeviceId did = getDeviceId();
323 + ChassisId cid = new ChassisId();
324 + DeviceDescription desc = new DefaultDeviceDescription(
325 + did.uri(),
326 + Device.Type.OTHER,
327 + "", "",
328 + "", "",
329 + cid);
330 + if (NetconfDeviceProvider.log.isDebugEnabled()) {
331 + NetconfDeviceProvider.log.debug("Persisting Device"
332 + + did.uri().toString());
333 + }
334 +
335 + netconfDeviceMap.put(did, device);
336 + providerService.deviceConnected(did, desc);
337 + if (NetconfDeviceProvider.log.isDebugEnabled()) {
338 + NetconfDeviceProvider.log
339 + .debug("Done with Device Info Creation on ONOS core. Device Info: "
340 + + device.deviceInfo()
341 + + " "
342 + + did.uri().toString());
343 + }
344 + delay(EVENTINTERVAL);
345 + } catch (URISyntaxException e) {
346 + NetconfDeviceProvider.log
347 + .error("Syntax Error while creating URI for the device: "
348 + + device.deviceInfo()
349 + + " couldn't persist the device onto the store",
350 + e);
351 + } catch (Exception e) {
352 + NetconfDeviceProvider.log
353 + .error("Error while initializing session for the device: "
354 + + device.deviceInfo(), e);
355 + }
356 + }
357 +
358 + /**
359 + * This will build a device id for the device.
360 + */
361 + private DeviceId getDeviceId() throws URISyntaxException {
362 + String additionalSSP = new StringBuilder(device.getUsername())
363 + .append("@").append(device.getSshHost()).append(":")
364 + .append(device.getSshPort()).toString();
365 + DeviceId did = DeviceId.deviceId(new URI(SCHEME, additionalSSP,
366 + null));
367 + return did;
368 + }
369 + }
370 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +/**
18 + * Provider that uses Netconf capability request as a means of infrastructure device discovery.
19 + */
20 +package org.onosproject.provider.netconf.device.impl;
...\ No newline at end of file ...\ No newline at end of file
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2015 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<project xmlns="http://maven.apache.org/POM/4.0.0"
18 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
20 + <modelVersion>4.0.0</modelVersion>
21 +
22 + <parent>
23 + <groupId>org.onosproject</groupId>
24 + <artifactId>onos-providers</artifactId>
25 + <version>1.2.0-SNAPSHOT</version>
26 + <relativePath>../pom.xml</relativePath>
27 + </parent>
28 +
29 + <artifactId>onos-netconf-providers</artifactId>
30 + <packaging>pom</packaging>
31 +
32 + <description>ONOS Netconf protocol adapters</description>
33 +
34 + <modules>
35 + <module>device</module>
36 + </modules>
37 +
38 + <dependencies>
39 + <dependency>
40 + <groupId>org.onosproject</groupId>
41 + <artifactId>onos-api</artifactId>
42 + <classifier>tests</classifier>
43 + <scope>test</scope>
44 + </dependency>
45 + </dependencies>
46 +
47 +</project>
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
35 <module>openflow</module> 35 <module>openflow</module>
36 <module>lldp</module> 36 <module>lldp</module>
37 <module>host</module> 37 <module>host</module>
38 + <module>netconf</module>
38 <module>null</module> 39 <module>null</module>
39 </modules> 40 </modules>
40 41
......
1 +#
2 +# Instance-specific configurations, in this case, the number of
3 +# devices per node.
4 +#
5 +devConfigs = cisco:cisco@192.168.56.20:2022:inactive,sdn:rocks@192.168.56.30:22:inactive
6 +
7 +#
8 +# Number of ports per device. This is global to all devices
9 +# on all instances.
10 +#
11 +# numPorts = 8