andrea
Committed by Gerrit Code Review

[ONOS-3253/3144] Insert support for Netconf device configuration, set and get controllers commands

Change-Id: I99188aa18207b9d0b0d935b9f9e61e547f4ddab1
Showing 33 changed files with 1812 additions and 1161 deletions
...@@ -59,8 +59,11 @@ public class DeviceSetControllersCommand extends AbstractShellCommand { ...@@ -59,8 +59,11 @@ public class DeviceSetControllersCommand extends AbstractShellCommand {
59 ControllerConfig config = h.behaviour(ControllerConfig.class); 59 ControllerConfig config = h.behaviour(ControllerConfig.class);
60 print("before:"); 60 print("before:");
61 config.getControllers().forEach(c -> print(c.target())); 61 config.getControllers().forEach(c -> print(c.target()));
62 - 62 + try {
63 config.setControllers(newControllers); 63 config.setControllers(newControllers);
64 + } catch (NullPointerException e) {
65 + print("No Device with requested parameters {} ", uri);
66 + }
64 print("after:"); 67 print("after:");
65 config.getControllers().forEach(c -> print(c.target())); 68 config.getControllers().forEach(c -> print(c.target()));
66 print("size %d", config.getControllers().size()); 69 print("size %d", config.getControllers().size());
......
...@@ -24,5 +24,7 @@ ...@@ -24,5 +24,7 @@
24 24
25 <bundle>mvn:${project.groupId}/onos-ovsdb-api/${project.version}</bundle> 25 <bundle>mvn:${project.groupId}/onos-ovsdb-api/${project.version}</bundle>
26 <bundle>mvn:${project.groupId}/onos-ovsdb-rfc/${project.version}</bundle> 26 <bundle>mvn:${project.groupId}/onos-ovsdb-rfc/${project.version}</bundle>
27 +
28 + <bundle>mvn:${project.groupId}/onos-netconf-api/${project.version}</bundle>
27 </feature> 29 </feature>
28 </features> 30 </features>
......
...@@ -67,6 +67,11 @@ ...@@ -67,6 +67,11 @@
67 <artifactId>easymock</artifactId> 67 <artifactId>easymock</artifactId>
68 <scope>test</scope> 68 <scope>test</scope>
69 </dependency> 69 </dependency>
70 + <dependency>
71 + <groupId>org.onosproject</groupId>
72 + <artifactId>onos-netconf-api</artifactId>
73 + <version>${project.version}</version>
74 + </dependency>
70 75
71 <dependency> 76 <dependency>
72 <groupId>org.apache.felix</groupId> 77 <groupId>org.apache.felix</groupId>
......
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 +package org.onosproject.driver.netconf;
18 +
19 +import com.google.common.base.Preconditions;
20 +import org.onosproject.net.DeviceId;
21 +import org.onosproject.net.behaviour.ControllerConfig;
22 +import org.onosproject.net.behaviour.ControllerInfo;
23 +import org.onosproject.net.driver.AbstractHandlerBehaviour;
24 +import org.onosproject.net.driver.DriverHandler;
25 +import org.onosproject.netconf.NetconfController;
26 +import org.onosproject.netconf.NetconfDevice;
27 +import org.slf4j.Logger;
28 +
29 +import java.io.ByteArrayInputStream;
30 +import java.nio.charset.StandardCharsets;
31 +import java.util.ArrayList;
32 +import java.util.List;
33 +
34 +import static org.slf4j.LoggerFactory.getLogger;
35 +
36 +/**
37 + * Implementation of controller config which allows to get and set controllers
38 + * through the Netconf protocol.
39 + */
40 +public class NetconfControllerConfig extends AbstractHandlerBehaviour
41 + implements ControllerConfig {
42 +
43 + private final Logger log = getLogger(NetconfControllerConfig.class);
44 +
45 + @Override
46 + public List<ControllerInfo> getControllers() {
47 + DriverHandler handler = handler();
48 + NetconfController controller = handler.get(NetconfController.class);
49 + DeviceId ofDeviceId = handler.data().deviceId();
50 + Preconditions.checkNotNull(controller, "Netconf controller is null");
51 + List<ControllerInfo> controllers = new ArrayList<>();
52 + controllers.addAll(XmlConfigParser.parseStreamControllers(XmlConfigParser.
53 + loadXml(new ByteArrayInputStream(controller.
54 + getDevicesMap().get(ofDeviceId).getSession().
55 + getConfig("running").getBytes(StandardCharsets.UTF_8)))));
56 + return controllers;
57 + }
58 +
59 + @Override
60 + public void setControllers(List<ControllerInfo> controllers) {
61 + DriverHandler handler = handler();
62 + NetconfController controller = handler.get(NetconfController.class);
63 + DeviceId deviceId = handler.data().deviceId();
64 + Preconditions.checkNotNull(controller, "Netconf controller is null");
65 + try {
66 + NetconfDevice device = controller.getNetconfDevice(deviceId);
67 + log.warn("provider map {}", controller.getDevicesMap());
68 + String config = XmlConfigParser.createControllersConfig(
69 + XmlConfigParser.loadXml(getClass().getResourceAsStream("controllers.xml")),
70 + XmlConfigParser.loadXml(
71 + new ByteArrayInputStream(device.getSession()
72 + .getConfig("running")
73 + .getBytes(
74 + StandardCharsets.UTF_8))),
75 + "running", "merge", "create", controllers
76 + );
77 + device.getSession().editConfig(config.substring(config.indexOf("-->") + 3));
78 + } catch (NullPointerException e) {
79 + log.warn("No NETCONF device with requested parameters " + e);
80 + throw new NullPointerException("No NETCONF device with requested parameters " + e);
81 + }
82 +
83 + }
84 +
85 + //TODO maybe put method getNetconfClientService like in ovsdb if we need it
86 +
87 +}
88 +
89 +
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 +package org.onosproject.driver.netconf;
18 +
19 +import org.apache.commons.configuration.ConfigurationException;
20 +import org.apache.commons.configuration.HierarchicalConfiguration;
21 +import org.apache.commons.configuration.XMLConfiguration;
22 +import org.apache.commons.configuration.tree.ConfigurationNode;
23 +import org.onlab.packet.IpAddress;
24 +import org.onosproject.net.behaviour.ControllerInfo;
25 +import org.slf4j.Logger;
26 +import org.slf4j.LoggerFactory;
27 +
28 +import java.io.InputStream;
29 +import java.io.StringWriter;
30 +import java.util.ArrayList;
31 +import java.util.List;
32 +
33 +/**
34 + * Parser for Netconf XML configurations and replys.
35 + */
36 +final class XmlConfigParser {
37 + public static final Logger log = LoggerFactory
38 + .getLogger(XmlConfigParser.class);
39 +
40 + private XmlConfigParser() {
41 + //not called, preventing any allocation
42 + }
43 +
44 +
45 + protected static HierarchicalConfiguration loadXml(InputStream xmlStream) {
46 + XMLConfiguration cfg = new XMLConfiguration();
47 + try {
48 + cfg.load(xmlStream);
49 + return cfg;
50 + } catch (ConfigurationException e) {
51 + throw new IllegalArgumentException("Cannot load xml from Stream", e);
52 + }
53 + }
54 +
55 + protected static List<ControllerInfo> parseStreamControllers(HierarchicalConfiguration cfg) {
56 + List<ControllerInfo> controllers = new ArrayList<>();
57 + List<HierarchicalConfiguration> fields =
58 + cfg.configurationsAt("data.capable-switch." +
59 + "logical-switches." +
60 + "switch.controllers.controller");
61 + for (HierarchicalConfiguration sub : fields) {
62 + controllers.add(new ControllerInfo(
63 + IpAddress.valueOf(sub.getString("ip-address")),
64 + Integer.parseInt(sub.getString("port")),
65 + sub.getString("protocol")));
66 + }
67 + return controllers;
68 + }
69 +
70 + protected static String parseSwitchId(HierarchicalConfiguration cfg) {
71 + HierarchicalConfiguration field =
72 + cfg.configurationAt("data.capable-switch." +
73 + "logical-switches." +
74 + "switch");
75 + return field.getProperty("id").toString();
76 + }
77 +
78 + protected static String parseCapableSwitchId(HierarchicalConfiguration cfg) {
79 + HierarchicalConfiguration field =
80 + cfg.configurationAt("data.capable-switch");
81 + return field.getProperty("id").toString();
82 + }
83 +
84 + protected static String createControllersConfig(HierarchicalConfiguration cfg,
85 + HierarchicalConfiguration actualCfg,
86 + String target, String netconfOperation,
87 + String controllerOperation,
88 + List<ControllerInfo> controllers) {
89 + //cfg.getKeys().forEachRemaining(key -> System.out.println(key));
90 + cfg.setProperty("edit-config.target", target);
91 + cfg.setProperty("edit-config.default-operation", netconfOperation);
92 + cfg.setProperty("edit-config.config.capable-switch.id",
93 + parseCapableSwitchId(actualCfg));
94 + cfg.setProperty("edit-config.config.capable-switch." +
95 + "logical-switches.switch.id", parseSwitchId(actualCfg));
96 + List<ConfigurationNode> newControllers = new ArrayList<>();
97 + for (ControllerInfo ci : controllers) {
98 + XMLConfiguration controller = new XMLConfiguration();
99 + controller.setRoot(new HierarchicalConfiguration.Node("controller"));
100 + String id = ci.type() + ":" + ci.ip() + ":" + ci.port();
101 + controller.setProperty("id", id);
102 + controller.setProperty("ip-address", ci.ip());
103 + controller.setProperty("port", ci.port());
104 + controller.setProperty("protocol", ci.type());
105 + newControllers.add(controller.getRootNode());
106 + }
107 + cfg.addNodes("edit-config.config.capable-switch.logical-switches." +
108 + "switch.controllers", newControllers);
109 + XMLConfiguration editcfg = (XMLConfiguration) cfg;
110 + StringWriter stringWriter = new StringWriter();
111 + try {
112 + editcfg.save(stringWriter);
113 + } catch (ConfigurationException e) {
114 + e.printStackTrace();
115 + }
116 + String s = stringWriter.toString()
117 + .replaceAll("<controller>",
118 + "<controller nc:operation=\"" + controllerOperation + "\">");
119 + s = s.replace("<target>" + target + "</target>",
120 + "<target><" + target + "/></target>");
121 + return s;
122 +
123 + }
124 +
125 + //TODO implement mor methods for parsing configuration when you need them
126 +}
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 + * Implementations of the Netconf driver behaviours.
19 + */
20 +package org.onosproject.driver.netconf;
...\ No newline at end of file ...\ No newline at end of file
...@@ -37,6 +37,13 @@ ...@@ -37,6 +37,13 @@
37 <behaviour api="org.onosproject.net.behaviour.ExtensionResolver" 37 <behaviour api="org.onosproject.net.behaviour.ExtensionResolver"
38 impl="org.onosproject.driver.extensions.NiciraExtensionInterpreter" /> 38 impl="org.onosproject.driver.extensions.NiciraExtensionInterpreter" />
39 </driver> 39 </driver>
40 + <driver name="ovs-netconf" extends="default"
41 + manufacturer="Nicira, Inc\." hwVersion="Open vSwitch" swVersion="2\..*">
42 + <behaviour api="org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver"
43 + impl="org.onosproject.driver.handshaker.NiciraSwitchHandshaker"/>
44 + <behaviour api="org.onosproject.net.behaviour.ControllerConfig"
45 + impl="org.onosproject.driver.netconf.NetconfControllerConfig"/>
46 + </driver>
40 <driver name="ovs-corsa" extends="ovs" 47 <driver name="ovs-corsa" extends="ovs"
41 manufacturer="Corsa" hwVersion="emulation" swVersion="0.0.0"> 48 manufacturer="Corsa" hwVersion="emulation" swVersion="0.0.0">
42 <behaviour api="org.onosproject.net.behaviour.Pipeliner" 49 <behaviour api="org.onosproject.net.behaviour.Pipeliner"
......
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 +<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
18 + <edit-config>
19 + <target>
20 + </target>
21 + <default-operation>
22 + </default-operation>
23 + <config>
24 + <capable-switch xmlns="urn:onf:config:yang">
25 + <id></id>
26 + <logical-switches>
27 + <switch>
28 + <id></id>
29 + <controllers>
30 + </controllers>
31 + </switch>
32 + </logical-switches>
33 + </capable-switch>
34 + </config>
35 + </edit-config>
36 +</rpc>
...\ No newline at end of file ...\ No newline at end of file
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 +package org.onosproject.driver.netconf;
18 +
19 +import org.junit.Test;
20 +import org.onlab.packet.IpAddress;
21 +import org.onosproject.net.behaviour.ControllerInfo;
22 +
23 +import java.io.IOException;
24 +import java.io.InputStream;
25 +import java.util.ArrayList;
26 +import java.util.Arrays;
27 +import java.util.List;
28 +
29 +import static org.junit.Assert.assertTrue;
30 +import static org.onosproject.driver.netconf.XmlConfigParser.*;
31 +
32 +//import static org.junit.Assert.*;
33 +
34 +/**
35 + * Test the XML document Parsing for netconf configuration.
36 + */
37 +public class XmlConfigParserTest {
38 +
39 +
40 + @Test
41 + public void basics() throws IOException {
42 + InputStream stream = getClass().getResourceAsStream("testConfig.xml");
43 + List<ControllerInfo> controllers = parseStreamControllers(loadXml(stream));
44 + assertTrue(controllers.get(0).equals(new ControllerInfo(
45 + IpAddress.valueOf("10.128.12.1"), 6653, "tcp")));
46 + assertTrue(controllers.get(1).equals(new ControllerInfo(
47 + IpAddress.valueOf("10.128.12.2"), 6654, "tcp")));
48 +
49 + }
50 +
51 + @Test
52 + public void switchId() {
53 + InputStream stream = getClass().getResourceAsStream("testConfig.xml");
54 + String switchId = parseSwitchId(loadXml(stream));
55 + assertTrue(switchId.equals("ofc-bridge"));
56 + }
57 +
58 + @Test
59 + public void capableSwitchId() {
60 + InputStream stream = getClass().getResourceAsStream("testConfig.xml");
61 + String capableSwitchId = parseCapableSwitchId(loadXml(stream));
62 + assertTrue(capableSwitchId.equals("openvswitch"));
63 + }
64 +
65 + @Test
66 + public void controllersConfig() {
67 + InputStream streamOrig = getClass().getResourceAsStream("testConfig.xml");
68 + InputStream streamCFG = XmlConfigParser.class
69 + .getResourceAsStream("controllers.xml");
70 + String config = createControllersConfig(loadXml(streamCFG),
71 + loadXml(streamOrig), "running", "merge",
72 + "create", new ArrayList<>(Arrays.asList(
73 + new ControllerInfo(IpAddress.valueOf("192.168.1.1"),
74 + 5000, "tcp"))));
75 + assertTrue(config.contains("192.168.1.1"));
76 + assertTrue(config.contains("tcp"));
77 + assertTrue(config.contains("5000"));
78 +
79 + }
80 +}
...\ 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 +
18 +<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="7">
19 + <data>
20 + <capable-switch xmlns="urn:onf:config:yang">
21 + <id>openvswitch</id>
22 + <resources>
23 + <port>
24 + <name>ofc-bridge</name>
25 + <requested-number>666</requested-number>
26 + <configuration>
27 + <admin-state>down</admin-state>
28 + <no-receive>false</no-receive>
29 + <no-forward>false</no-forward>
30 + <no-packet-in>false</no-packet-in>
31 + </configuration>
32 + </port>
33 + </resources>
34 + <logical-switches>
35 + <switch>
36 + <id>ofc-bridge</id>
37 + <datapath-id>00:01:02:03:04:05:06:07</datapath-id>
38 + <lost-connection-behavior>failSecureMode</lost-connection-behavior>
39 + <controllers>
40 + <controller>
41 + <id>(null)</id>
42 + <ip-address>10.128.12.1</ip-address>
43 + <port>6653</port>
44 + <protocol>tcp</protocol>
45 + </controller>
46 + <controller>
47 + <id>(null)</id>
48 + <ip-address>10.128.12.2</ip-address>
49 + <port>6654</port>
50 + <protocol>tcp</protocol>
51 + </controller>
52 + </controllers>
53 + <resources>
54 + <port>ofc-bridge</port>
55 + </resources>
56 + </switch>
57 + </logical-switches>
58 + </capable-switch>
59 + </data>
60 +</rpc-reply>
...\ No newline at end of file ...\ No newline at end of file
...@@ -40,11 +40,6 @@ ...@@ -40,11 +40,6 @@
40 <artifactId>netty-transport-native-epoll</artifactId> 40 <artifactId>netty-transport-native-epoll</artifactId>
41 <version>${netty4.version}</version> 41 <version>${netty4.version}</version>
42 </dependency> 42 </dependency>
43 - <dependency>
44 - <groupId>org.onosproject</groupId>
45 - <artifactId>onos-netconf-rfc</artifactId>
46 - <version>${project.version}</version>
47 - </dependency>
48 </dependencies> 43 </dependencies>
49 44
50 </project> 45 </project>
......
1 -package org.onosproject.netconf;
2 -
3 -/**
4 - * Created by tom on 10/19/15.
5 - */
6 -public class Foo {
7 -}
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 +package org.onosproject.netconf;
18 +
19 +import org.onlab.packet.IpAddress;
20 +import org.onosproject.net.DeviceId;
21 +
22 +import java.util.Map;
23 +
24 +/**
25 + * Abstraction of an NETCONF controller. Serves as a one stop shop for obtaining
26 + * NetconfDevice and (un)register listeners on NETCONF device events.
27 + */
28 +public interface NetconfController {
29 +
30 + /**
31 + * Adds Device Event Listener.
32 + *
33 + * @param listener node listener
34 + */
35 + void addDeviceListener(NetconfDeviceListener listener);
36 +
37 + /**
38 + * Removes Device Listener.
39 + *
40 + * @param listener node listener
41 + */
42 + void removeDeviceListener(NetconfDeviceListener listener);
43 +
44 + /**
45 + * Tries to connect to a specific NETCONF device, if the connection is succesful
46 + * it creates and adds the device to the ONOS core as a NetconfDevice.
47 + *
48 + * @param deviceInfo info about the device to add
49 + * @return NetconfDevice Netconf device
50 + */
51 + NetconfDevice connectDevice(NetconfDeviceInfo deviceInfo);
52 +
53 + /**
54 + * Removes a Netconf device.
55 + *
56 + * @param deviceInfo info about the device to remove
57 + */
58 + void removeDevice(NetconfDeviceInfo deviceInfo);
59 +
60 + /**
61 + * Gets all the nodes information.
62 + *
63 + * @return map of devices
64 + */
65 + Map<DeviceId, NetconfDevice> getDevicesMap();
66 +
67 + /**
68 + * Gets a Netconf Device by node identifier.
69 + *
70 + * @param deviceInfo node identifier
71 + * @return NetconfDevice Netconf device
72 + */
73 + NetconfDevice getNetconfDevice(DeviceId deviceInfo);
74 +
75 + /**
76 + * Gets a Netconf Device by node identifier.
77 + *
78 + * @param ip device ip
79 + * @param port device port
80 + * @return NetconfDevice Netconf device
81 + */
82 + NetconfDevice getNetconfDevice(IpAddress ip, int port);
83 +
84 +}
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 +package org.onosproject.netconf;
18 +
19 +/**
20 + * Interface representing a NETCONF device.
21 + */
22 +public interface NetconfDevice {
23 +
24 +
25 + /**
26 + * Returns whether a device is a NETCONF device with a capabilities list
27 + * and is accessible.
28 + *
29 + * @return true if device is accessible, false otherwise
30 + */
31 + boolean isActive();
32 +
33 + /**
34 + * Returns a NETCONF session context for this device.
35 + *
36 + * @return netconf session
37 + */
38 + NetconfSession getSession();
39 +
40 + /**
41 + * Ensures that all sessions are closed.
42 + * A device cannot be used after disconnect is called.
43 + */
44 + void disconnect();
45 +
46 + /**
47 + * return all the info associated with this device.
48 + * @return NetconfDeviceInfo
49 + */
50 + NetconfDeviceInfo getDeviceInfo();
51 +}
...\ No newline at end of file ...\ No newline at end of file
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 +package org.onosproject.netconf;
18 +
19 +import com.google.common.base.Preconditions;
20 +import org.onlab.packet.IpAddress;
21 +import org.onosproject.net.DeviceId;
22 +import org.slf4j.Logger;
23 +import org.slf4j.LoggerFactory;
24 +
25 +import java.io.File;
26 +import java.net.URI;
27 +import java.net.URISyntaxException;
28 +import java.util.Objects;
29 +
30 +/**
31 + * Represents a Netconf device information.
32 + */
33 +public class NetconfDeviceInfo {
34 +
35 + public static final Logger log = LoggerFactory
36 + .getLogger(NetconfDeviceInfo.class);
37 +
38 + private String name;
39 + private String password;
40 + private IpAddress ipAddress;
41 + private int port;
42 + private File keyFile;
43 +
44 +
45 + /**
46 + * Information for contacting the controller.
47 + *
48 + * @param name the connection type
49 + * @param password the password for the device
50 + * @param ipAddress the ip address
51 + * @param port the tcp port
52 + */
53 + public NetconfDeviceInfo(String name, String password, IpAddress ipAddress,
54 + int port) {
55 + Preconditions.checkArgument(!name.equals(""), "Empty device name");
56 + Preconditions.checkNotNull(port > 0, "Negative port");
57 + Preconditions.checkNotNull(ipAddress, "Null ip address");
58 + this.name = name;
59 + this.password = password;
60 + this.ipAddress = ipAddress;
61 + this.port = port;
62 + }
63 +
64 + /**
65 + * Information for contacting the controller.
66 + *
67 + * @param name the connection type
68 + * @param password the password for the device
69 + * @param ipAddress the ip address
70 + * @param port the tcp port
71 + * @param keyString the string cointaing the key.
72 + */
73 + public NetconfDeviceInfo(String name, String password, IpAddress ipAddress,
74 + int port, String keyString) {
75 + Preconditions.checkArgument(!name.equals(""), "Empty device name");
76 + Preconditions.checkNotNull(port > 0, "Negative port");
77 + Preconditions.checkNotNull(ipAddress, "Null ip address");
78 + this.name = name;
79 + this.password = password;
80 + this.ipAddress = ipAddress;
81 + this.port = port;
82 + this.keyFile = new File(keyString);
83 + }
84 +
85 + /**
86 + * Exposes the name of the controller.
87 + *
88 + * @return String name
89 + */
90 + public String name() {
91 + return name;
92 + }
93 +
94 + /**
95 + * Exposes the password of the controller.
96 + *
97 + * @return String password
98 + */
99 + public String password() {
100 + return password;
101 + }
102 +
103 + /**
104 + * Exposes the ip address of the controller.
105 + *
106 + * @return IpAddress ip address
107 + */
108 + public IpAddress ip() {
109 + return ipAddress;
110 + }
111 +
112 + /**
113 + * Exposes the port of the controller.
114 + *
115 + * @return int port address
116 + */
117 + public int port() {
118 + return port;
119 + }
120 +
121 + /**
122 + * Exposes the keyFile of the controller.
123 + *
124 + * @return int port address
125 + */
126 + public File getKeyFile() {
127 + return keyFile;
128 + }
129 +
130 + /**
131 + * Return the info about the device in a string.
132 + * String format: "netconf:name@ip:port"
133 + *
134 + * @return String device info
135 + */
136 + public String toString() {
137 + return "netconf:" + name + "@" + ipAddress + ":" + port;
138 + }
139 +
140 + /**
141 + * Return the DeviceId about the device containing the URI.
142 + *
143 + * @return DeviceId
144 + */
145 + public DeviceId getDeviceId() {
146 +
147 + try {
148 + return DeviceId.deviceId(new URI(this.toString()));
149 + } catch (URISyntaxException e) {
150 + log.debug("Unable to build deviceID for device {} ", this, e);
151 + }
152 + return null;
153 + }
154 +
155 + @Override
156 + public int hashCode() {
157 + return Objects.hash(ipAddress, port, name);
158 + }
159 +
160 + @Override
161 + public boolean equals(Object toBeCompared) {
162 + if (toBeCompared instanceof NetconfDeviceInfo) {
163 + NetconfDeviceInfo netconfDeviceInfo = (NetconfDeviceInfo) toBeCompared;
164 + if (netconfDeviceInfo.name().equals(name)
165 + && netconfDeviceInfo.ip().equals(ipAddress)
166 + && netconfDeviceInfo.port() == port
167 + && netconfDeviceInfo.password().equals(password)) {
168 + return true;
169 + }
170 + }
171 + return false;
172 + }
173 +}
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 +package org.onosproject.netconf;
18 +
19 +/**
20 + * Allows for providers interested in node events to be notified.
21 + */
22 +public interface NetconfDeviceListener {
23 +
24 + /**
25 + * Notifies that the node was added.
26 + *
27 + * @param nodeId the node where the event occurred
28 + */
29 + void deviceAdded(NetconfDeviceInfo nodeId);
30 +
31 + /**
32 + * Notifies that the node was removed.
33 + *
34 + * @param nodeId the node where the event occurred
35 + */
36 + void deviceRemoved(NetconfDeviceInfo nodeId);
37 +}
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 +package org.onosproject.netconf;
18 +
19 +import java.util.List;
20 +
21 +/**
22 + * NETCONF session object that allows NETCONF operations on top with the physical
23 + * device on top of an SSH connection.
24 + */
25 +// TODO change return type of methdos to <Capability, XMLdoc, string or yang obj>
26 +public interface NetconfSession {
27 +
28 + /**
29 + * Retrives the requested configuration, different from get-config.
30 + * @param request the XML containing the request to the server.
31 + * @return device running configuration
32 + */
33 + String get(String request);
34 +
35 + /**
36 + * Executes an RPC to the server.
37 + * @param request the XML containing the RPC for the server.
38 + * @return Server response or ERROR
39 + */
40 + String doRPC(String request);
41 +
42 + /**
43 + * Retrives the specified configuration.
44 + *
45 + * @param targetConfiguration the type of configuration to retrieve.
46 + * @return specified configuration.
47 + */
48 + String getConfig(String targetConfiguration);
49 +
50 + /**
51 + * Retrives part of the specivied configuration based on the filterSchema.
52 + *
53 + * @param targetConfiguration the type of configuration to retrieve.
54 + * @param configurationFilterSchema XML schema to filter the configuration
55 + * elements we are interested in
56 + * @return device running configuration.
57 + */
58 + String getConfig(String targetConfiguration, String configurationFilterSchema);
59 +
60 + /**
61 + * Retrives part of the specified configuration based on the filterSchema.
62 + *
63 + * @param newConfiguration configuration to set
64 + * @return true if the configuration was edited correctly
65 + */
66 +
67 + boolean editConfig(String newConfiguration);
68 +
69 + /**
70 + * Copies the new configuration, an Url or a complete configuration xml tree
71 + * to the target configuration.
72 + * The target configuration can't be the running one
73 + *
74 + * @param targetConfiguration the type of configuration to retrieve.
75 + * @param newConfiguration configuration to set
76 + * @return true if the configuration was copied correctly
77 + */
78 + boolean copyConfig(String targetConfiguration, String newConfiguration);
79 +
80 + /**
81 + * Deletes part of the specified configuration based on the filterSchema.
82 + *
83 + * @param targetConfiguration the name of the configuration to delete
84 + * @return true if the configuration was copied correctly
85 + */
86 + boolean deleteConfig(String targetConfiguration);
87 +
88 + /**
89 + * Locks the candidate configuration.
90 + *
91 + * @return true if successful.
92 + */
93 + boolean lock();
94 +
95 + /**
96 + * Unlocks the candidate configuration.
97 + *
98 + * @return true if successful.
99 + */
100 + boolean unlock();
101 +
102 + /**
103 + * Closes the Netconf session with the device.
104 + * the first time it tries gracefully, then kills it forcefully
105 + * @return true if closed
106 + */
107 + boolean close();
108 +
109 + /**
110 + * Gets the session ID of the Netconf session.
111 + *
112 + * @return Session ID as a string.
113 + */
114 + String getSessionId();
115 +
116 + /**
117 + * Gets the capabilities of the Netconf server associated to this session.
118 + *
119 + * @return Network capabilities as a string.
120 + */
121 + String getServerCapabilities();
122 +
123 + /**
124 + * Sets the device capabilities.
125 + * @param capabilities list of capabilities the device has.
126 + */
127 + void setDeviceCapabilities(List<String> capabilities);
128 +
129 +}
...@@ -39,9 +39,53 @@ ...@@ -39,9 +39,53 @@
39 <version>${project.version}</version> 39 <version>${project.version}</version>
40 </dependency> 40 </dependency>
41 <dependency> 41 <dependency>
42 - <groupId>org.onosproject</groupId> 42 + <groupId>ch.ethz.ganymed</groupId>
43 - <artifactId>onos-netconf-rfc</artifactId> 43 + <artifactId>ganymed-ssh2</artifactId>
44 - <version>${project.version}</version> 44 + <version>262</version>
45 </dependency> 45 </dependency>
46 </dependencies> 46 </dependencies>
47 +
48 + <build>
49 + <plugins>
50 + <!--plugin>
51 + <groupId>org.apache.maven.plugins</groupId>
52 + <artifactId>maven-shade-plugin</artifactId>
53 + <version>2.3</version>
54 + <configuration>
55 + <filters>
56 + <filter>
57 + <artifact>ch.ethz.ganymed:ganymed-ssh2</artifact>
58 + <includes>
59 + <include>ch/ethz/ssh2/**</include>
60 + </includes>
61 + </filter>
62 + <filter>
63 + <artifact>org.jdom:jdom2</artifact>
64 + <includes>
65 + <include>org/jdom2/**</include>
66 + </includes>
67 + </filter>
68 + </filters>
69 + </configuration>
70 + <executions>
71 + <execution>
72 + <phase>package</phase>
73 + <goals>
74 + <goal>shade</goal>
75 + </goals>
76 + </execution>
77 + </executions>
78 + </plugin-->
79 + <plugin>
80 + <groupId>org.apache.felix</groupId>
81 + <artifactId>maven-bundle-plugin</artifactId>
82 + <configuration>
83 + <instructions>
84 + <Private-Package>ch.ethz.ssh2.*</Private-Package>
85 + <Embed-Dependecy>ganymed-ssh2</Embed-Dependecy>
86 + </instructions>
87 + </configuration>
88 + </plugin>
89 + </plugins>
90 + </build>
47 </project> 91 </project>
......
1 -package org.onosproject.netconf.ctl;
2 -
3 -/**
4 - * Created by tom on 10/19/15.
5 - */
6 -public class Foo {
7 -}
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 +package org.onosproject.netconf.ctl;
18 +
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Component;
21 +import org.apache.felix.scr.annotations.Deactivate;
22 +import org.apache.felix.scr.annotations.Service;
23 +import org.onlab.packet.IpAddress;
24 +import org.onosproject.net.DeviceId;
25 +import org.onosproject.netconf.NetconfController;
26 +import org.onosproject.netconf.NetconfDevice;
27 +import org.onosproject.netconf.NetconfDeviceInfo;
28 +import org.onosproject.netconf.NetconfDeviceListener;
29 +import org.osgi.service.component.ComponentContext;
30 +import org.slf4j.Logger;
31 +import org.slf4j.LoggerFactory;
32 +
33 +import java.io.IOException;
34 +import java.util.Map;
35 +import java.util.Set;
36 +import java.util.concurrent.ConcurrentHashMap;
37 +import java.util.concurrent.CopyOnWriteArraySet;
38 +
39 +/**
40 + * The implementation of NetconfController.
41 + */
42 +@Component(immediate = true)
43 +@Service
44 +public class NetconfControllerImpl implements NetconfController {
45 +
46 + public static final Logger log = LoggerFactory
47 + .getLogger(NetconfControllerImpl.class);
48 +
49 + public Map<DeviceId, NetconfDevice> netconfDeviceMap = new ConcurrentHashMap<>();
50 +
51 + protected Set<NetconfDeviceListener> netconfDeviceListeners = new CopyOnWriteArraySet<>();
52 +
53 + @Activate
54 + public void activate(ComponentContext context) {
55 + log.info("Started");
56 + }
57 +
58 + @Deactivate
59 + public void deactivate() {
60 + netconfDeviceMap.clear();
61 + log.info("Stopped");
62 + }
63 +
64 + @Override
65 + public void addDeviceListener(NetconfDeviceListener listener) {
66 + if (!netconfDeviceListeners.contains(listener)) {
67 + netconfDeviceListeners.add(listener);
68 + }
69 + }
70 +
71 + @Override
72 + public void removeDeviceListener(NetconfDeviceListener listener) {
73 + netconfDeviceListeners.remove(listener);
74 + }
75 +
76 + @Override
77 + public NetconfDevice getNetconfDevice(DeviceId deviceInfo) {
78 + return netconfDeviceMap.get(deviceInfo);
79 + }
80 +
81 + @Override
82 + public NetconfDevice getNetconfDevice(IpAddress ip, int port) {
83 + NetconfDevice device = null;
84 + for (DeviceId info : netconfDeviceMap.keySet()) {
85 + if (IpAddress.valueOf(info.uri().getHost()).equals(ip) &&
86 + info.uri().getPort() == port) {
87 + return netconfDeviceMap.get(info);
88 + }
89 + }
90 + return device;
91 + }
92 +
93 + @Override
94 + public NetconfDevice connectDevice(NetconfDeviceInfo deviceInfo) {
95 + if (netconfDeviceMap.containsKey(deviceInfo.getDeviceId())) {
96 + log.warn("Device {} is already present");
97 + return netconfDeviceMap.get(deviceInfo.getDeviceId());
98 + } else {
99 + log.info("Creating NETCONF device {}", deviceInfo);
100 + return createDevice(deviceInfo);
101 + }
102 + }
103 +
104 + @Override
105 + public void removeDevice(NetconfDeviceInfo deviceInfo) {
106 + if (netconfDeviceMap.containsKey(deviceInfo.getDeviceId())) {
107 + log.warn("Device {} is not present");
108 + } else {
109 + stopDevice(deviceInfo);
110 + }
111 + }
112 +
113 + private NetconfDevice createDevice(NetconfDeviceInfo deviceInfo) {
114 + NetconfDevice netconfDevice = null;
115 + try {
116 + netconfDevice = new NetconfDeviceImpl(deviceInfo);
117 + for (NetconfDeviceListener l : netconfDeviceListeners) {
118 + l.deviceAdded(deviceInfo);
119 + }
120 + netconfDeviceMap.put(deviceInfo.getDeviceId(), netconfDevice);
121 + } catch (IOException e) {
122 + throw new IllegalStateException("Cannot create NETCONF device " +
123 + "with device Info: " +
124 + deviceInfo + " \n" + e);
125 + }
126 + return netconfDevice;
127 + }
128 +
129 + private void stopDevice(NetconfDeviceInfo deviceInfo) {
130 + netconfDeviceMap.get(deviceInfo.getDeviceId()).disconnect();
131 + netconfDeviceMap.remove(deviceInfo.getDeviceId());
132 + for (NetconfDeviceListener l : netconfDeviceListeners) {
133 + l.deviceRemoved(deviceInfo);
134 + }
135 + }
136 +
137 + @Override
138 + public Map<DeviceId, NetconfDevice> getDevicesMap() {
139 + return netconfDeviceMap;
140 + }
141 +
142 +
143 +}
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 +package org.onosproject.netconf.ctl;
18 +
19 +import org.onosproject.netconf.NetconfDevice;
20 +import org.onosproject.netconf.NetconfDeviceInfo;
21 +import org.onosproject.netconf.NetconfSession;
22 +
23 +import java.io.IOException;
24 +
25 +/**
26 + * Implementation of a NETCONF device.
27 + */
28 +public class NetconfDeviceImpl implements NetconfDevice {
29 +
30 + private NetconfDeviceInfo netconfDeviceInfo;
31 + private boolean deviceState = false;
32 + private NetconfSession netconfSession;
33 + //private String config;
34 +
35 + public NetconfDeviceImpl(NetconfDeviceInfo deviceInfo) throws IOException {
36 + netconfDeviceInfo = deviceInfo;
37 + try {
38 + netconfSession = new NetconfSessionImpl(netconfDeviceInfo);
39 + } catch (IOException e) {
40 + throw new IOException("Cannot create connection and session", e);
41 + }
42 + deviceState = true;
43 + //config = netconfSession.getConfig("running");
44 + }
45 +
46 + @Override
47 + public boolean isActive() {
48 + return deviceState;
49 + }
50 +
51 + @Override
52 + public NetconfSession getSession() {
53 + return netconfSession;
54 + }
55 +
56 + @Override
57 + public void disconnect() {
58 + deviceState = false;
59 + netconfSession.close();
60 + }
61 +
62 + @Override
63 + public NetconfDeviceInfo getDeviceInfo() {
64 + return netconfDeviceInfo;
65 + }
66 +}
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 +package org.onosproject.netconf.ctl;
18 +
19 +import ch.ethz.ssh2.Connection;
20 +import ch.ethz.ssh2.Session;
21 +import com.google.common.base.Preconditions;
22 +import org.onosproject.netconf.NetconfDeviceInfo;
23 +import org.onosproject.netconf.NetconfSession;
24 +import org.slf4j.Logger;
25 +import org.slf4j.LoggerFactory;
26 +
27 +import java.io.BufferedReader;
28 +import java.io.IOException;
29 +import java.io.InputStreamReader;
30 +import java.io.PrintWriter;
31 +import java.io.StringWriter;
32 +import java.util.ArrayList;
33 +import java.util.Arrays;
34 +import java.util.List;
35 +
36 +/**
37 + * Implementation of a NETCONF session to talk to a device.
38 + */
39 +public class NetconfSessionImpl implements NetconfSession {
40 +
41 + public static final Logger log = LoggerFactory
42 + .getLogger(NetconfSessionImpl.class);
43 + private static final int CONNECTION_TIMEOUT = 0;
44 +
45 +
46 + private Connection netconfConnection;
47 + private NetconfDeviceInfo deviceInfo;
48 + private Session sshSession;
49 + private boolean connectionActive;
50 + private BufferedReader bufferReader = null;
51 + private PrintWriter out = null;
52 + private int messageID = 0;
53 +
54 + private List<String> deviceCapabilities =
55 + new ArrayList<>(
56 + Arrays.asList("urn:ietf:params:netconf:base:1.0"));
57 +
58 + private String serverCapabilities;
59 + private String endpattern = "]]>]]>";
60 +
61 +
62 + public NetconfSessionImpl(NetconfDeviceInfo deviceInfo) throws IOException {
63 + this.deviceInfo = deviceInfo;
64 + connectionActive = false;
65 + startConnection();
66 + }
67 +
68 +
69 + private void startConnection() throws IOException {
70 + if (!connectionActive) {
71 + netconfConnection = new Connection(deviceInfo.ip().toString(), deviceInfo.port());
72 + netconfConnection.connect(null, CONNECTION_TIMEOUT, 0);
73 + boolean isAuthenticated;
74 + try {
75 + if (deviceInfo.getKeyFile() != null) {
76 + isAuthenticated = netconfConnection.authenticateWithPublicKey(
77 + deviceInfo.name(), deviceInfo.getKeyFile(),
78 + deviceInfo.password());
79 + } else {
80 + log.info("authenticate with username {} and password {}",
81 + deviceInfo.name(), deviceInfo.password());
82 + isAuthenticated = netconfConnection.authenticateWithPassword(
83 + deviceInfo.name(), deviceInfo.password());
84 + }
85 + } catch (IOException e) {
86 + throw new IOException("Authentication connection failed:" +
87 + e.getMessage());
88 + }
89 +
90 + connectionActive = true;
91 + Preconditions.checkArgument(isAuthenticated,
92 + "Authentication password and username failed");
93 + startSshSession();
94 + }
95 + }
96 +
97 + private void startSshSession() throws IOException {
98 + try {
99 + sshSession = netconfConnection.openSession();
100 + sshSession.startSubSystem("netconf");
101 + bufferReader = new BufferedReader(new InputStreamReader(
102 + sshSession.getStdout()));
103 + out = new PrintWriter(sshSession.getStdin());
104 + sendHello();
105 + } catch (IOException e) {
106 + throw new IOException("Failed to create ch.ethz.ssh2.Session session:" +
107 + e.getMessage());
108 + }
109 + }
110 +
111 + private void sendHello() throws IOException {
112 + serverCapabilities = doRequest(createHelloString());
113 + }
114 +
115 + private String createHelloString() {
116 + StringBuilder hellobuffer = new StringBuilder();
117 + hellobuffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
118 + hellobuffer.append("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
119 + hellobuffer.append(" <capabilities>\n");
120 + deviceCapabilities.forEach(
121 + cap -> hellobuffer.append(" <capability>" + cap + "</capability>\n"));
122 + hellobuffer.append(" </capabilities>\n");
123 + hellobuffer.append("</hello>\n");
124 + hellobuffer.append(endpattern);
125 + return hellobuffer.toString();
126 +
127 + }
128 +
129 + @Override
130 + public String doRPC(String request) {
131 + String reply = "ERROR";
132 + try {
133 + reply = doRequest(request);
134 + if (checkReply(reply)) {
135 + return reply;
136 + } else {
137 + return "ERROR " + reply;
138 + }
139 + } catch (IOException e) {
140 + log.error("Problem in the reading from the SSH connection " + e);
141 + }
142 + return reply;
143 + }
144 +
145 + private String doRequest(String request) throws IOException {
146 + log.info("sshState " + sshSession.getState() + "request" + request);
147 + if (sshSession.getState() != 2) {
148 + try {
149 + startSshSession();
150 + } catch (IOException e) {
151 + log.info("the connection had to be reopened");
152 + startConnection();
153 + }
154 + sendHello();
155 + }
156 + log.info("sshState after" + sshSession.getState());
157 + out.print(request);
158 + out.flush();
159 + messageID++;
160 + return readOne();
161 + }
162 +
163 + @Override
164 + public String get(String request) {
165 + return doRPC(request);
166 + }
167 +
168 + @Override
169 + public String getConfig(String targetConfiguration) {
170 + return getConfig(targetConfiguration, null);
171 + }
172 +
173 + @Override
174 + public String getConfig(String targetConfiguration, String configurationSchema) {
175 + StringBuilder rpc = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
176 + rpc.append("<rpc message-id=\"" + messageID + "\" "
177 + + "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
178 + rpc.append("<get-config>\n");
179 + rpc.append("<source>\n");
180 + rpc.append("<" + targetConfiguration + "/>");
181 + rpc.append("</source>");
182 + if (configurationSchema != null) {
183 + rpc.append("<filter type=\"subtree\">\n");
184 + rpc.append(configurationSchema + "\n");
185 + rpc.append("</filter>\n");
186 + }
187 + rpc.append("</get-config>\n");
188 + rpc.append("</rpc>\n");
189 + rpc.append(endpattern);
190 + String reply = null;
191 + try {
192 + reply = doRequest(rpc.toString());
193 + } catch (IOException e) {
194 + e.printStackTrace();
195 + }
196 +
197 + return checkReply(reply) ? reply : null;
198 + }
199 +
200 + @Override
201 + public boolean editConfig(String newConfiguration) {
202 + newConfiguration = newConfiguration + endpattern;
203 + String reply = null;
204 + try {
205 + reply = doRequest(newConfiguration);
206 + } catch (IOException e) {
207 + e.printStackTrace();
208 + }
209 + return checkReply(reply);
210 + }
211 +
212 + @Override
213 + public boolean copyConfig(String targetConfiguration, String newConfiguration) {
214 + newConfiguration = newConfiguration.trim();
215 + if (!newConfiguration.startsWith("<configuration>")) {
216 + newConfiguration = "<configuration>" + newConfiguration
217 + + "</configuration>";
218 + }
219 + StringBuilder rpc = new StringBuilder("<?xml version=\"1.0\" " +
220 + "encoding=\"UTF-8\"?>");
221 + rpc.append("<rpc>");
222 + rpc.append("<copy-config>");
223 + rpc.append("<target>");
224 + rpc.append("<" + targetConfiguration + "/>");
225 + rpc.append("</target>");
226 + rpc.append("<source>");
227 + rpc.append("<" + newConfiguration + "/>");
228 + rpc.append("</source>");
229 + rpc.append("</copy-config>");
230 + rpc.append("</rpc>");
231 + rpc.append(endpattern);
232 + String reply = null;
233 + try {
234 + reply = doRequest(rpc.toString());
235 + } catch (IOException e) {
236 + e.printStackTrace();
237 + }
238 +
239 + return checkReply(reply);
240 + }
241 +
242 + @Override
243 + public boolean deleteConfig(String targetConfiguration) {
244 + if (targetConfiguration.equals("running")) {
245 + log.warn("Target configuration for delete operation can't be \"running\"",
246 + targetConfiguration);
247 + return false;
248 + }
249 + StringBuilder rpc = new StringBuilder("<?xml version=\"1.0\" " +
250 + "encoding=\"UTF-8\"?>");
251 + rpc.append("<rpc>");
252 + rpc.append("<delete-config>");
253 + rpc.append("<target>");
254 + rpc.append("<" + targetConfiguration + "/>");
255 + rpc.append("</target>");
256 + rpc.append("</delete-config>");
257 + rpc.append("</rpc>");
258 + rpc.append(endpattern);
259 + String reply = null;
260 + try {
261 + reply = doRequest(rpc.toString());
262 + } catch (IOException e) {
263 + e.printStackTrace();
264 + }
265 +
266 + return checkReply(reply);
267 + }
268 +
269 + @Override
270 + public boolean lock() {
271 + StringBuilder rpc = new StringBuilder("<?xml version=\"1.0\" " +
272 + "encoding=\"UTF-8\"?>");
273 + rpc.append("<rpc>");
274 + rpc.append("<lock>");
275 + rpc.append("<target>");
276 + rpc.append("<candidate/>");
277 + rpc.append("</target>");
278 + rpc.append("</lock>");
279 + rpc.append("</rpc>");
280 + rpc.append(endpattern);
281 + String reply = null;
282 + try {
283 + reply = doRequest(rpc.toString());
284 + } catch (IOException e) {
285 + e.printStackTrace();
286 + }
287 + return checkReply(reply);
288 + }
289 +
290 + @Override
291 + public boolean unlock() {
292 + StringBuilder rpc = new StringBuilder("<?xml version=\"1.0\" " +
293 + "encoding=\"UTF-8\"?>");
294 + rpc.append("<rpc>");
295 + rpc.append("<unlock>");
296 + rpc.append("<target>");
297 + rpc.append("<candidate/>");
298 + rpc.append("</target>");
299 + rpc.append("</unlock>");
300 + rpc.append("</rpc>");
301 + rpc.append(endpattern);
302 + String reply = null;
303 + try {
304 + reply = doRequest(rpc.toString());
305 + } catch (IOException e) {
306 + e.printStackTrace();
307 + }
308 + return checkReply(reply);
309 + }
310 +
311 + @Override
312 + public boolean close() {
313 + return close(false);
314 + }
315 +
316 + private boolean close(boolean force) {
317 + StringBuilder rpc = new StringBuilder();
318 + rpc.append("<rpc>");
319 + if (force) {
320 + rpc.append("<kill-configuration/>");
321 + } else {
322 + rpc.append("<close-configuration/>");
323 + }
324 + rpc.append("<close-configuration/>");
325 + rpc.append("</rpc>");
326 + rpc.append(endpattern);
327 + return checkReply(rpc.toString()) ? true : close(true);
328 + }
329 +
330 + @Override
331 + public String getSessionId() {
332 + if (serverCapabilities.contains("<session-id>")) {
333 + String[] outer = serverCapabilities.split("<session-id>");
334 + Preconditions.checkArgument(outer.length != 1,
335 + "Error in retrieving the session id");
336 + String[] value = outer[1].split("</session-id>");
337 + Preconditions.checkArgument(value.length != 1,
338 + "Error in retrieving the session id");
339 + return value[0];
340 + } else {
341 + return String.valueOf(-1);
342 + }
343 + }
344 +
345 + @Override
346 + public String getServerCapabilities() {
347 + return serverCapabilities;
348 + }
349 +
350 + @Override
351 + public void setDeviceCapabilities(List<String> capabilities) {
352 + deviceCapabilities = capabilities;
353 + }
354 +
355 + private boolean checkReply(String reply) {
356 + if (reply != null) {
357 + if (!reply.contains("<rpc-error>")) {
358 + return true;
359 + } else if (reply.contains("<ok/>")
360 + || (reply.contains("<rpc-error>")
361 + && reply.contains("warning"))) {
362 + return true;
363 + }
364 + }
365 + return false;
366 + }
367 +
368 + private String readOne() throws IOException {
369 + //TODO try a simple string
370 + final StringWriter reply = new StringWriter();
371 + while (true) {
372 + int charRead = bufferReader.read();
373 + if (charRead == -1) {
374 + throw new IOException("Session closed");
375 + }
376 +
377 + for (int i = 0; i < endpattern.length(); i++) {
378 + if (charRead == endpattern.charAt(i)) {
379 + if (i < endpattern.length() - 1) {
380 + charRead = bufferReader.read();
381 + } else {
382 + return reply.getBuffer().toString();
383 + }
384 + } else {
385 + String s = endpattern.substring(0, i);
386 + for (int j = 0; i < s.length(); j++) {
387 + reply.write(s.charAt(j));
388 + }
389 + reply.write(charRead);
390 + break;
391 + }
392 + }
393 + }
394 + }
395 +
396 +}
...@@ -27,6 +27,12 @@ ...@@ -27,6 +27,12 @@
27 <artifactId>onos-netconf</artifactId> 27 <artifactId>onos-netconf</artifactId>
28 <packaging>pom</packaging> 28 <packaging>pom</packaging>
29 29
30 + <modules>
31 + <module>api</module>
32 + <module>rfc</module>
33 + <module>ctl</module>
34 + </modules>
35 +
30 <description>ONOS NETCONF southbound libraries</description> 36 <description>ONOS NETCONF southbound libraries</description>
31 <dependencies> 37 <dependencies>
32 <dependency> 38 <dependency>
...@@ -54,6 +60,11 @@ ...@@ -54,6 +60,11 @@
54 <groupId>org.apache.felix</groupId> 60 <groupId>org.apache.felix</groupId>
55 <artifactId>org.apache.felix.scr.annotations</artifactId> 61 <artifactId>org.apache.felix.scr.annotations</artifactId>
56 </dependency> 62 </dependency>
63 + <dependency>
64 + <groupId>org.onosproject</groupId>
65 + <artifactId>onos-core-net</artifactId>
66 + <version>${project.version}</version>
67 + </dependency>
57 </dependencies> 68 </dependencies>
58 69
59 <build> 70 <build>
...@@ -68,10 +79,4 @@ ...@@ -68,10 +79,4 @@
68 </plugin> 79 </plugin>
69 </plugins> 80 </plugins>
70 </build> 81 </build>
71 -
72 - <modules>
73 - <module>api</module>
74 - <module>rfc</module>
75 - <module>ctl</module>
76 - </modules>
77 </project> 82 </project>
......
...@@ -27,5 +27,4 @@ ...@@ -27,5 +27,4 @@
27 27
28 <artifactId>onos-netconf-rfc</artifactId> 28 <artifactId>onos-netconf-rfc</artifactId>
29 <packaging>bundle</packaging> 29 <packaging>bundle</packaging>
30 -
31 </project> 30 </project>
......
...@@ -19,6 +19,13 @@ ...@@ -19,6 +19,13 @@
19 features="${project.artifactId}"> 19 features="${project.artifactId}">
20 <description>${project.description}</description> 20 <description>${project.description}</description>
21 21
22 + <artifact>mvn:${project.groupId}/onos-netconf-rfc/${project.version}</artifact>
23 + <artifact>mvn:${project.groupId}/onos-netconf-api/${project.version}</artifact>
24 + <artifact>mvn:${project.groupId}/onos-netconf-ctl/${project.version}</artifact>
25 + <artifact>mvn:${project.groupId}/onos-drivers/${project.version}</artifact>
26 +
22 <artifact>mvn:${project.groupId}/onos-netconf-provider-device/${project.version}</artifact> 27 <artifact>mvn:${project.groupId}/onos-netconf-provider-device/${project.version}</artifact>
28 +
29 + <!--<artifact>mvn:${project.groupId}/onos-netconf-provider-device/${project.version}</artifact>-->
23 <!-- Question: should there be the jnc stuff here? Or is it just for testing --> 30 <!-- Question: should there be the jnc stuff here? Or is it just for testing -->
24 </app> 31 </app>
......
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
20 description="${project.description}"> 20 description="${project.description}">
21 <feature>onos-api</feature> 21 <feature>onos-api</feature>
22 <bundle>mvn:io.netty/netty/3.9.2.Final</bundle> 22 <bundle>mvn:io.netty/netty/3.9.2.Final</bundle>
23 + <bundle>mvn:${project.groupId}/onos-netconf-api/${project.version}</bundle>
24 + <bundle>mvn:${project.groupId}/onos-netconf-ctl/${project.version}</bundle>
25 +
23 <bundle>mvn:${project.groupId}/onos-netconf-provider-device/${project.version}</bundle> 26 <bundle>mvn:${project.groupId}/onos-netconf-provider-device/${project.version}</bundle>
24 <!-- Question: should there be the jnc stuff here? Or is it just for testing --> 27 <!-- Question: should there be the jnc stuff here? Or is it just for testing -->
25 </feature> 28 </feature>
......
...@@ -33,129 +33,29 @@ ...@@ -33,129 +33,29 @@
33 33
34 <dependencies> 34 <dependencies>
35 <dependency> 35 <dependency>
36 - <groupId>org.osgi</groupId>
37 - <artifactId>org.osgi.compendium</artifactId>
38 - </dependency>
39 - <dependency>
40 - <groupId>ch.ethz.ganymed</groupId>
41 - <artifactId>ganymed-ssh2</artifactId>
42 - <version>262</version>
43 - </dependency>
44 - <dependency>
45 - <!-- TODO: change this appropriately when the official TailF JNC is available -->
46 <groupId>org.onosproject</groupId> 36 <groupId>org.onosproject</groupId>
47 - <artifactId>jnc</artifactId> 37 + <artifactId>onlab-junit</artifactId>
48 - <version>1.0</version> 38 + <scope>test</scope>
49 - </dependency>
50 - <dependency>
51 - <groupId>org.jdom</groupId>
52 - <artifactId>jdom2</artifactId>
53 - <version>2.0.5</version>
54 - </dependency>
55 - <dependency>
56 - <groupId>jaxen</groupId>
57 - <artifactId>jaxen</artifactId>
58 - <version>1.1.4</version>
59 - <optional>true</optional>
60 - </dependency>
61 - <dependency>
62 - <groupId>org.osgi</groupId>
63 - <artifactId>org.osgi.core</artifactId>
64 </dependency> 39 </dependency>
65 <dependency> 40 <dependency>
66 <groupId>org.onosproject</groupId> 41 <groupId>org.onosproject</groupId>
67 - <artifactId>onlab-junit</artifactId> 42 + <artifactId>onos-netconf-api</artifactId>
68 - <scope>test</scope> 43 + <version>${project.version}</version>
69 </dependency> 44 </dependency>
70 <dependency> 45 <dependency>
71 - <groupId>org.easymock</groupId> 46 + <groupId>org.onosproject</groupId>
72 - <artifactId>easymock</artifactId> 47 + <artifactId>onos-netconf-ctl</artifactId>
73 - <scope>test</scope> 48 + <version>${project.version}</version>
74 </dependency> 49 </dependency>
75 </dependencies> 50 </dependencies>
76 51
77 <build> 52 <build>
78 <plugins> 53 <plugins>
79 <plugin> 54 <plugin>
80 - <groupId>org.apache.maven.plugins</groupId>
81 - <artifactId>maven-shade-plugin</artifactId>
82 - <version>2.3</version>
83 - <configuration>
84 - <filters>
85 - <filter>
86 - <artifact>com.tailf:JNC</artifact>
87 - <includes>
88 - <include>com/tailf/jnc/**</include>
89 - </includes>
90 - </filter>
91 - <filter>
92 - <artifact>ch.ethz.ganymed:ganymed-ssh2</artifact>
93 - <includes>
94 - <include>ch/ethz/ssh2/**</include>
95 - </includes>
96 - </filter>
97 - <filter>
98 - <artifact>org.jdom:jdom2</artifact>
99 - <includes>
100 - <include>org/jdom2/**</include>
101 - </includes>
102 - </filter>
103 - </filters>
104 - </configuration>
105 - <executions>
106 - <execution>
107 - <phase>package</phase>
108 - <goals>
109 - <goal>shade</goal>
110 - </goals>
111 - </execution>
112 - </executions>
113 - </plugin>
114 - <plugin>
115 <groupId>org.apache.felix</groupId> 55 <groupId>org.apache.felix</groupId>
116 <artifactId>maven-scr-plugin</artifactId> 56 <artifactId>maven-scr-plugin</artifactId>
117 </plugin> 57 </plugin>
118 <plugin> 58 <plugin>
119 - <groupId>org.apache.felix</groupId>
120 - <artifactId>maven-bundle-plugin</artifactId>
121 - <configuration>
122 - <instructions>
123 - <Export-Package>
124 - com.tailf.jnc,
125 - ch.ethz.ssh2,
126 - ch.ethz.ssh2.auth,
127 - ch.ethz.ssh2.channel,
128 - ch.ethz.ssh2.crypto,
129 - ch.ethz.ssh2.crypto.cipher,
130 - ch.ethz.ssh2.crypto.dh,
131 - ch.ethz.ssh2.crypto.digest,
132 - ch.ethz.ssh2.log,
133 - ch.ethz.ssh2.packets,
134 - ch.ethz.ssh2.server,
135 - ch.ethz.ssh2.sftp,
136 - ch.ethz.ssh2.signature,
137 - ch.ethz.ssh2.transport,
138 - ch.ethz.ssh2.util,
139 - org.jdom2,
140 - org.jdom2.input,
141 - org.jdom2.output,
142 - org.jdom2.adapters,
143 - org.jdom2.filter,
144 - org.jdom2.internal,
145 - org.jdom2.located,
146 - org.jdom2.transform,
147 - org.jdom2.util,
148 - org.jdom2.xpath,
149 - org.jdom2.input.sax,
150 - org.jdom2.input.stax,
151 - org.jdom2.output.support,
152 - org.jdom2.xpath.jaxen,
153 - org.jdom2.xpath.util
154 - </Export-Package>
155 - </instructions>
156 - </configuration>
157 - </plugin>
158 - <plugin>
159 <groupId>org.onosproject</groupId> 59 <groupId>org.onosproject</groupId>
160 <artifactId>onos-maven-plugin</artifactId> 60 <artifactId>onos-maven-plugin</artifactId>
161 </plugin> 61 </plugin>
......
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 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 inactive state of the device */
55 - INACTIVE,
56 - /* Used to specify invalid state of the device */
57 - INVALID
58 - }
59 -
60 - private static final int DEFAULT_SSH_PORT = 22;
61 - private static final int DEFAULT_CON_TIMEOUT = 0;
62 - private static final String XML_CAPABILITY_KEY = "capability";
63 - private static final int EVENTINTERVAL = 2000;
64 - private static final int CONNECTION_CHECK_INTERVAL = 3;
65 - private static final String INPUT_HELLO_XML_MSG = new StringBuilder(
66 - "<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
67 - .append("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">")
68 - .append("<capabilities><capability>urn:ietf:params:netconf:base:1.0</capability>")
69 - .append("</capabilities></hello>").toString();
70 -
71 - private String sshHost;
72 - private int sshPort = DEFAULT_SSH_PORT;
73 - private int connectTimeout = DEFAULT_CON_TIMEOUT;
74 - private String username;
75 - private String password;
76 - private boolean reachable = false;
77 -
78 - private List<String> capabilities = new ArrayList<String>();
79 - private SSHConnection sshConnection = null;
80 -
81 - private DeviceState deviceState = DeviceState.INVALID;
82 -
83 - protected NetconfDevice(String sshHost, int sshPort, String username,
84 - String password) {
85 - this.username = checkNotNull(username,
86 - "Netconf Username Cannot be null");
87 - this.sshHost = checkNotNull(sshHost, "Netconf Device IP cannot be null");
88 - this.sshPort = checkNotNull(sshPort,
89 - "Netconf Device SSH port cannot be null");
90 - this.password = password;
91 - }
92 -
93 - /**
94 - * This will try to connect to NETCONF device and find all the capabilities.
95 - *
96 - * @throws Exception if unable to connect to the device
97 - */
98 - // FIXME: this should not be a generic Exception; perhaps wrap in some RuntimeException
99 - public void init() throws Exception {
100 - try {
101 - if (sshConnection == null) {
102 - sshConnection = new SSHConnection(sshHost, sshPort, connectTimeout);
103 - sshConnection.authenticateWithPassword(username, password);
104 - }
105 - // Send hello message to retrieve capabilities.
106 - } catch (IOException e) {
107 - log.error("Fatal Error while creating connection to the device: "
108 - + deviceInfo(), e);
109 - throw e;
110 - } catch (JNCException e) {
111 - log.error("Failed to connect to the device: " + deviceInfo(), e);
112 - throw e;
113 - }
114 -
115 - hello();
116 - }
117 -
118 - private void hello() {
119 - SSHSession ssh = null;
120 - try {
121 - ssh = new SSHSession(sshConnection);
122 - String helloRequestXML = INPUT_HELLO_XML_MSG.trim();
123 -
124 - log.debug("++++++++++++++++++++++++++++++++++Sending Hello: "
125 - + sshConnection.getGanymedConnection().getHostname()
126 - + "++++++++++++++++++++++++++++++++++");
127 - printPrettyXML(helloRequestXML);
128 - ssh.print(helloRequestXML);
129 - // ssh.print(endCharSeq);
130 - ssh.flush();
131 - String xmlResponse = null;
132 - int i = CONNECTION_CHECK_INTERVAL;
133 - while (!ssh.ready() && i > 0) {
134 - delay(EVENTINTERVAL);
135 - i--;
136 - }
137 -
138 - if (ssh.ready()) {
139 - StringBuffer readOne = ssh.readOne();
140 - if (readOne == null) {
141 - log.error("The Hello Contains No Capabilites");
142 - throw new JNCException(
143 - JNCException.SESSION_ERROR,
144 - "server does not support NETCONF base capability: "
145 - + Capabilities.NETCONF_BASE_CAPABILITY);
146 - } else {
147 - xmlResponse = readOne.toString().trim();
148 -
149 - log.debug("++++++++++++++++++++++++++++++++++Reading Capabilities: "
150 - + sshConnection.getGanymedConnection()
151 - .getHostname()
152 - + "++++++++++++++++++++++++++++++++++");
153 -
154 - printPrettyXML(xmlResponse);
155 - processCapabilities(xmlResponse);
156 - }
157 - }
158 - reachable = true;
159 - } catch (IOException e) {
160 - log.error("Fatal Error while sending Hello Message to the device: "
161 - + deviceInfo(), e);
162 - } catch (JNCException e) {
163 - log.error("Fatal Error while sending Hello Message to the device: "
164 - + deviceInfo(), e);
165 - } finally {
166 - log.debug("Closing the session after successful execution");
167 - if (ssh != null) {
168 - ssh.close();
169 - }
170 - }
171 - }
172 -
173 - private void processCapabilities(String xmlResponse) throws JNCException {
174 - if (xmlResponse.isEmpty()) {
175 - log.error("The capability response cannot be empty");
176 - throw new JNCException(
177 - JNCException.SESSION_ERROR,
178 - "server does not support NETCONF base capability: "
179 - + Capabilities.NETCONF_BASE_CAPABILITY);
180 - }
181 - try {
182 - Document doc = new SAXBuilder()
183 - .build(new StringReader(xmlResponse));
184 - Element rootElement = doc.getRootElement();
185 - processCapabilities(rootElement);
186 - } catch (Exception e) {
187 - log.error("ERROR while parsing the XML " + xmlResponse);
188 - }
189 - }
190 -
191 - private void processCapabilities(Element rootElement) {
192 - List<Element> children = rootElement.getChildren();
193 - if (children.isEmpty()) {
194 - return;
195 - }
196 - for (Element child : children) {
197 -
198 - if (child.getName().equals(XML_CAPABILITY_KEY)) {
199 - capabilities.add(child.getValue());
200 - }
201 - if (!child.getChildren().isEmpty()) {
202 - processCapabilities(child);
203 - }
204 - }
205 - }
206 -
207 - private void printPrettyXML(String xmlstring) {
208 - try {
209 - Document doc = new SAXBuilder().build(new StringReader(xmlstring));
210 - XMLOutputter xmOut = new XMLOutputter(Format.getPrettyFormat());
211 - String outputString = xmOut.outputString(doc);
212 - log.debug(outputString);
213 - } catch (Exception e) {
214 - log.error("ERROR while parsing the XML " + xmlstring, e);
215 -
216 - }
217 - }
218 -
219 - /**
220 - * This would return host IP and host Port, used by this particular Netconf
221 - * Device.
222 - * @return Device Information.
223 - */
224 - public String deviceInfo() {
225 - return new StringBuilder("host: ").append(sshHost).append(". port: ")
226 - .append(sshPort).toString();
227 - }
228 -
229 - /**
230 - * This will terminate the device connection.
231 - */
232 - public void disconnect() {
233 - sshConnection.close();
234 - reachable = false;
235 - }
236 -
237 - /**
238 - * This will list down all the capabilities supported on the device.
239 - * @return Capability list.
240 - */
241 - public List<String> getCapabilities() {
242 - return capabilities;
243 - }
244 -
245 - /**
246 - * This api is intended to know whether the device is connected or not.
247 - * @return true if connected
248 - */
249 - public boolean isReachable() {
250 - return reachable;
251 - }
252 -
253 - /**
254 - * This will return the IP used connect ssh on the device.
255 - * @return Netconf Device IP
256 - */
257 - public String getSshHost() {
258 - return sshHost;
259 - }
260 -
261 - /**
262 - * This will return the SSH Port used connect the device.
263 - * @return SSH Port number
264 - */
265 - public int getSshPort() {
266 - return sshPort;
267 - }
268 -
269 - /**
270 - * The usename used to connect Netconf Device.
271 - * @return Device Username
272 - */
273 - public String getUsername() {
274 - return username;
275 - }
276 -
277 - /**
278 - * Retrieve current state of the device.
279 - * @return Current Device State
280 - */
281 - public DeviceState getDeviceState() {
282 - return deviceState;
283 - }
284 -
285 - /**
286 - * This is set the state information for the device.
287 - * @param deviceState Next Device State
288 - */
289 - public void setDeviceState(DeviceState deviceState) {
290 - this.deviceState = deviceState;
291 - }
292 -
293 - /**
294 - * Check whether the device is in Active state.
295 - * @return true if the device is Active
296 - */
297 - public boolean isActive() {
298 - return deviceState == DeviceState.ACTIVE ? true : false;
299 - }
300 -
301 - public void setConnectTimeout(int connectTimeout) {
302 - this.connectTimeout = connectTimeout;
303 - }
304 -}
...@@ -13,39 +13,28 @@ ...@@ -13,39 +13,28 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 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 16
24 -import java.io.IOException; 17 +package org.onosproject.provider.netconf.device.impl;
25 -import java.net.SocketTimeoutException;
26 -import java.net.URI;
27 -import java.net.URISyntaxException;
28 -import java.util.Dictionary;
29 -import java.util.Map;
30 -import java.util.Map.Entry;
31 -import java.util.concurrent.ConcurrentHashMap;
32 -import java.util.concurrent.ExecutorService;
33 -import java.util.concurrent.Executors;
34 -import java.util.concurrent.TimeUnit;
35 18
19 +import com.google.common.base.Preconditions;
36 import org.apache.felix.scr.annotations.Activate; 20 import org.apache.felix.scr.annotations.Activate;
37 import org.apache.felix.scr.annotations.Component; 21 import org.apache.felix.scr.annotations.Component;
38 import org.apache.felix.scr.annotations.Deactivate; 22 import org.apache.felix.scr.annotations.Deactivate;
39 -import org.apache.felix.scr.annotations.Modified;
40 -import org.apache.felix.scr.annotations.Property;
41 import org.apache.felix.scr.annotations.Reference; 23 import org.apache.felix.scr.annotations.Reference;
42 import org.apache.felix.scr.annotations.ReferenceCardinality; 24 import org.apache.felix.scr.annotations.ReferenceCardinality;
43 import org.onlab.packet.ChassisId; 25 import org.onlab.packet.ChassisId;
44 -import org.onosproject.cfg.ComponentConfigService; 26 +import org.onosproject.core.ApplicationId;
45 -import org.onosproject.cluster.ClusterService; 27 +import org.onosproject.core.CoreService;
28 +import org.onosproject.incubator.net.config.basics.ConfigException;
29 +import org.onosproject.net.DefaultAnnotations;
46 import org.onosproject.net.Device; 30 import org.onosproject.net.Device;
47 import org.onosproject.net.DeviceId; 31 import org.onosproject.net.DeviceId;
48 import org.onosproject.net.MastershipRole; 32 import org.onosproject.net.MastershipRole;
33 +import org.onosproject.net.SparseAnnotations;
34 +import org.onosproject.net.config.ConfigFactory;
35 +import org.onosproject.net.config.NetworkConfigEvent;
36 +import org.onosproject.net.config.NetworkConfigListener;
37 +import org.onosproject.net.config.NetworkConfigRegistry;
49 import org.onosproject.net.device.DefaultDeviceDescription; 38 import org.onosproject.net.device.DefaultDeviceDescription;
50 import org.onosproject.net.device.DeviceDescription; 39 import org.onosproject.net.device.DeviceDescription;
51 import org.onosproject.net.device.DeviceProvider; 40 import org.onosproject.net.device.DeviceProvider;
...@@ -54,305 +43,180 @@ import org.onosproject.net.device.DeviceProviderService; ...@@ -54,305 +43,180 @@ import org.onosproject.net.device.DeviceProviderService;
54 import org.onosproject.net.device.DeviceService; 43 import org.onosproject.net.device.DeviceService;
55 import org.onosproject.net.provider.AbstractProvider; 44 import org.onosproject.net.provider.AbstractProvider;
56 import org.onosproject.net.provider.ProviderId; 45 import org.onosproject.net.provider.ProviderId;
57 -import org.onosproject.provider.netconf.device.impl.NetconfDevice.DeviceState; 46 +import org.onosproject.netconf.NetconfController;
58 -import org.osgi.service.component.ComponentContext; 47 +import org.onosproject.netconf.NetconfDevice;
48 +import org.onosproject.netconf.NetconfDeviceInfo;
49 +import org.onosproject.netconf.NetconfDeviceListener;
59 import org.slf4j.Logger; 50 import org.slf4j.Logger;
60 51
52 +import java.util.Map;
53 +
54 +import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
55 +import static org.slf4j.LoggerFactory.getLogger;
56 +
61 /** 57 /**
62 - * Provider which will try to fetch the details of NETCONF devices from the core 58 + * Provider which uses an NETCONF controller to detect device.
63 - * and run a capability discovery on each of the device.
64 */ 59 */
65 @Component(immediate = true) 60 @Component(immediate = true)
66 public class NetconfDeviceProvider extends AbstractProvider 61 public class NetconfDeviceProvider extends AbstractProvider
67 implements DeviceProvider { 62 implements DeviceProvider {
68 - 63 + private final Logger log = getLogger(getClass());
69 - private final Logger log = getLogger(NetconfDeviceProvider.class);
70 -
71 - protected Map<DeviceId, NetconfDevice> netconfDeviceMap = new ConcurrentHashMap<DeviceId, NetconfDevice>();
72 -
73 - private DeviceProviderService providerService;
74 64
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 65 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected DeviceProviderRegistry providerRegistry; 66 protected DeviceProviderRegistry providerRegistry;
77 67
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 68 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected DeviceService deviceService; 69 protected DeviceService deviceService;
80 -
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 - protected ClusterService clusterService; 71 + protected NetconfController controller; //where is initiated ?
83 72
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 - protected ComponentConfigService cfgService; 74 + protected NetworkConfigRegistry cfgService;
86 -
87 - private ExecutorService deviceBuilder = Executors
88 - .newFixedThreadPool(1, groupedThreads("onos/netconf", "device-creator"));
89 -
90 - // Delay between events in ms.
91 - private static final int EVENTINTERVAL = 5;
92 -
93 - private static final String SCHEME = "netconf";
94 75
95 - @Property(name = "devConfigs", value = "", label = "Instance-specific configurations") 76 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 - private String devConfigs = null; 77 + protected CoreService coreService;
97 78
98 - @Property(name = "devPasswords", value = "", label = "Instance-specific password")
99 - private String devPasswords = null;
100 79
101 - /** 80 + private DeviceProviderService providerService;
102 - * Creates a provider with the supplier identifier. 81 + private NetconfDeviceListener innerNodeListener = new InnerNetconfDeviceListener();
103 - */ 82 + protected static final String ISNOTNULL = "NetconfDeviceInfo is not null";
104 - public NetconfDeviceProvider() { 83 + private static final String UNKNOWN = "unknown";
105 - super(new ProviderId("netconf", "org.onosproject.provider.netconf")); 84 +
85 + private final ConfigFactory factory =
86 + new ConfigFactory<ApplicationId, NetconfProviderConfig>(APP_SUBJECT_FACTORY,
87 + NetconfProviderConfig.class,
88 + "devices",
89 + true) {
90 + @Override
91 + public NetconfProviderConfig createConfig() {
92 + return new NetconfProviderConfig();
106 } 93 }
94 + };
95 + private final NetworkConfigListener cfgLister = new InternalNetworkConfigListener();
96 + private ApplicationId appId;
97 +
107 98
108 @Activate 99 @Activate
109 - public void activate(ComponentContext context) { 100 + public void activate() {
110 - cfgService.registerProperties(getClass());
111 providerService = providerRegistry.register(this); 101 providerService = providerRegistry.register(this);
112 - modified(context); 102 + cfgService.registerConfigFactory(factory);
103 + cfgService.addListener(cfgLister);
104 + controller.addDeviceListener(innerNodeListener);
105 + connectExistingDevices();
113 log.info("Started"); 106 log.info("Started");
114 } 107 }
115 108
109 +
116 @Deactivate 110 @Deactivate
117 - public void deactivate(ComponentContext context) { 111 + public void deactivate() {
118 - cfgService.unregisterProperties(getClass(), false);
119 - try {
120 - for (Entry<DeviceId, NetconfDevice> deviceEntry : netconfDeviceMap
121 - .entrySet()) {
122 - deviceBuilder.submit(new DeviceCreator(deviceEntry.getValue(),
123 - false));
124 - }
125 - deviceBuilder.awaitTermination(1000, TimeUnit.MILLISECONDS);
126 - } catch (InterruptedException e) {
127 - log.error("Device builder did not terminate");
128 - }
129 - deviceBuilder.shutdownNow();
130 - netconfDeviceMap.clear();
131 providerRegistry.unregister(this); 112 providerRegistry.unregister(this);
132 providerService = null; 113 providerService = null;
114 + cfgService.unregisterConfigFactory(factory);
133 log.info("Stopped"); 115 log.info("Stopped");
134 } 116 }
135 117
136 - @Modified 118 + public NetconfDeviceProvider() {
137 - public void modified(ComponentContext context) { 119 + super(new ProviderId("netconf", "org.onosproject.netconf.provider.device"));
138 - if (context == null) {
139 - log.info("No configuration file");
140 - return;
141 - }
142 - Dictionary<?, ?> properties = context.getProperties();
143 - String deviceCfgValue = get(properties, "devConfigs");
144 - log.info("Settings: devConfigs={}", deviceCfgValue);
145 - if (!isNullOrEmpty(deviceCfgValue)) {
146 - addOrRemoveDevicesConfig(deviceCfgValue);
147 - }
148 - }
149 -
150 - private void addOrRemoveDevicesConfig(String deviceConfig) {
151 - for (String deviceEntry : deviceConfig.split(",")) {
152 - NetconfDevice device = processDeviceEntry(deviceEntry);
153 - if (device != null) {
154 - log.info("Device Detail: username: {}, host={}, port={}, state={}",
155 - device.getUsername(), device.getSshHost(),
156 - device.getSshPort(), device.getDeviceState().name());
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 - log.info("No content for Device Entry, so cannot proceed further.");
169 - return null;
170 - }
171 - log.info("Trying to convert Device Entry String: " + deviceEntry
172 - + " to a Netconf Device Object");
173 - NetconfDevice device = null;
174 - try {
175 - String userInfo = deviceEntry.substring(0, deviceEntry
176 - .lastIndexOf('@'));
177 - String hostInfo = deviceEntry.substring(deviceEntry
178 - .lastIndexOf('@') + 1);
179 - String[] infoSplit = userInfo.split(":");
180 - String username = infoSplit[0];
181 - String password = infoSplit[1];
182 - infoSplit = hostInfo.split(":");
183 - String hostIp = infoSplit[0];
184 - Integer hostPort;
185 - try {
186 - hostPort = Integer.parseInt(infoSplit[1]);
187 - } catch (NumberFormatException nfe) {
188 - log.error("Bad Configuration Data: Failed to parse host port number string: "
189 - + infoSplit[1]);
190 - throw nfe;
191 - }
192 - String deviceState = infoSplit[2];
193 - if (isNullOrEmpty(username) || isNullOrEmpty(password)
194 - || isNullOrEmpty(hostIp) || hostPort == 0) {
195 - log.warn("Bad Configuration Data: both user and device information parts of Configuration "
196 - + deviceEntry + " should be non-nullable");
197 - } else {
198 - device = new NetconfDevice(hostIp, hostPort, username, password);
199 - if (!isNullOrEmpty(deviceState)) {
200 - if (deviceState.toUpperCase().equals(DeviceState.ACTIVE
201 - .name())) {
202 - device.setDeviceState(DeviceState.ACTIVE);
203 - } else if (deviceState.toUpperCase()
204 - .equals(DeviceState.INACTIVE.name())) {
205 - device.setDeviceState(DeviceState.INACTIVE);
206 - } else {
207 - log.warn("Device State Information can not be empty, so marking the state as INVALID");
208 - device.setDeviceState(DeviceState.INVALID);
209 - }
210 - } else {
211 - log.warn("The device entry do not specify state information, so marking the state as INVALID");
212 - device.setDeviceState(DeviceState.INVALID);
213 - }
214 - }
215 - } catch (ArrayIndexOutOfBoundsException aie) {
216 - log.error("Error while reading config infromation from the config file: "
217 - + "The user, host and device state infomation should be "
218 - + "in the order 'userInfo@hostInfo:deviceState'"
219 - + deviceEntry, aie);
220 - } catch (Exception e) {
221 - log.error("Error while parsing config information for the device entry: "
222 - + deviceEntry, e);
223 - }
224 - return device;
225 } 120 }
226 121
227 @Override 122 @Override
228 public void triggerProbe(DeviceId deviceId) { 123 public void triggerProbe(DeviceId deviceId) {
229 - // TODO Auto-generated method stub 124 + // TODO: This will be implemented later.
125 + log.info("Triggering probe on device {}", deviceId);
230 } 126 }
231 127
232 @Override 128 @Override
233 public void roleChanged(DeviceId deviceId, MastershipRole newRole) { 129 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
234 - 130 + // TODO: This will be implemented later.
235 } 131 }
236 132
237 @Override 133 @Override
238 public boolean isReachable(DeviceId deviceId) { 134 public boolean isReachable(DeviceId deviceId) {
239 - NetconfDevice netconfDevice = netconfDeviceMap.get(deviceId); 135 + Map<DeviceId, NetconfDevice> devices = controller.getDevicesMap();
136 +
137 + NetconfDevice netconfDevice = null;
138 + for (DeviceId key : devices.keySet()) {
139 + if (key.equals(deviceId)) {
140 + netconfDevice = controller.getDevicesMap().get(key);
141 + }
142 + }
240 if (netconfDevice == null) { 143 if (netconfDevice == null) {
241 log.warn("BAD REQUEST: the requested device id: " 144 log.warn("BAD REQUEST: the requested device id: "
242 + deviceId.toString() 145 + deviceId.toString()
243 + " is not associated to any NETCONF Device"); 146 + " is not associated to any NETCONF Device");
244 return false; 147 return false;
245 } 148 }
246 - return netconfDevice.isReachable(); 149 + return netconfDevice.isActive();
247 } 150 }
248 151
249 - /** 152 + private class InnerNetconfDeviceListener implements NetconfDeviceListener {
250 - * This class is intended to add or remove Configured Netconf Devices.
251 - * Functionality relies on 'createFlag' and 'NetconfDevice' content. The
252 - * functionality runs as a thread and dependening on the 'createFlag' value
253 - * it will create or remove Device entry from the core.
254 - */
255 - private class DeviceCreator implements Runnable {
256 153
257 - private NetconfDevice device; 154 + @Override
258 - private boolean createFlag; 155 + public void deviceAdded(NetconfDeviceInfo nodeId) {
156 + Preconditions.checkNotNull(nodeId, ISNOTNULL);
157 + DeviceId deviceId = nodeId.getDeviceId();
158 + //TODO filter for not netconf devices
159 + //Netconf configuration object
160 + ChassisId cid = new ChassisId();
161 + String ipAddress = nodeId.ip().toString();
162 + SparseAnnotations annotations = DefaultAnnotations.builder()
163 + .set("ipaddress", ipAddress).build();
164 + DeviceDescription deviceDescription = new DefaultDeviceDescription(
165 + deviceId.uri(),
166 + Device.Type.SWITCH,
167 + UNKNOWN, UNKNOWN,
168 + UNKNOWN, UNKNOWN,
169 + cid,
170 + annotations);
171 + providerService.deviceConnected(deviceId, deviceDescription);
259 172
260 - public DeviceCreator(NetconfDevice device, boolean createFlag) {
261 - this.device = device;
262 - this.createFlag = createFlag;
263 } 173 }
264 174
265 @Override 175 @Override
266 - public void run() { 176 + public void deviceRemoved(NetconfDeviceInfo nodeId) {
267 - if (createFlag) { 177 + Preconditions.checkNotNull(nodeId, ISNOTNULL);
268 - log.info("Trying to create Device Info on ONOS core"); 178 + DeviceId deviceId = nodeId.getDeviceId();
269 - advertiseDevices(); 179 + providerService.deviceDisconnected(deviceId);
270 - } else { 180 +
271 - log.info("Trying to remove Device Info on ONOS core");
272 - removeDevices();
273 } 181 }
274 } 182 }
275 183
276 - /** 184 + private void connectExistingDevices() {
277 - * For each Netconf Device, remove the entry from the device store. 185 + //TODO consolidate
278 - */ 186 + appId = coreService.registerApplication("org.onosproject.netconf");
279 - private void removeDevices() { 187 + connectDevices();
280 - if (device == null) {
281 - log.warn("The Request Netconf Device is null, cannot proceed further");
282 - return;
283 } 188 }
189 +
190 + private void connectDevices() {
191 + NetconfProviderConfig cfg = cfgService.getConfig(appId, NetconfProviderConfig.class);
192 + if (cfg != null) {
193 + log.info("cfg {}", cfg);
284 try { 194 try {
285 - DeviceId did = getDeviceId(); 195 + cfg.getDevicesAddresses().stream().forEach(addr -> controller
286 - if (!netconfDeviceMap.containsKey(did)) { 196 + .connectDevice(new NetconfDeviceInfo(addr.name(),
287 - log.error("BAD Request: 'Currently device is not discovered, " 197 + addr.password(),
288 - + "so cannot remove/disconnect the device: " 198 + addr.ip(),
289 - + device.deviceInfo() + "'"); 199 + addr.port())));
290 - return; 200 + } catch (ConfigException e) {
201 + log.error("Cannot read config error " + e);
291 } 202 }
292 - providerService.deviceDisconnected(did);
293 - device.disconnect();
294 - netconfDeviceMap.remove(did);
295 - delay(EVENTINTERVAL);
296 - } catch (URISyntaxException uriSyntaxExcpetion) {
297 - log.error("Syntax Error while creating URI for the device: "
298 - + device.deviceInfo()
299 - + " couldn't remove the device from the store",
300 - uriSyntaxExcpetion);
301 } 203 }
302 } 204 }
303 205
304 - /** 206 + private class InternalNetworkConfigListener implements NetworkConfigListener {
305 - * Initialize Netconf Device object, and notify core saying device 207 +
306 - * connected. 208 +
307 - */ 209 + @Override
308 - private void advertiseDevices() { 210 + public void event(NetworkConfigEvent event) {
309 - try { 211 + connectDevices();
310 - if (device == null) {
311 - log.warn("The Request Netconf Device is null, cannot proceed further");
312 - return;
313 - }
314 - device.init();
315 - DeviceId did = getDeviceId();
316 - ChassisId cid = new ChassisId();
317 - DeviceDescription desc = new DefaultDeviceDescription(
318 - did.uri(),
319 - Device.Type.OTHER,
320 - "", "",
321 - "", "",
322 - cid);
323 - log.info("Persisting Device" + did.uri().toString());
324 -
325 - netconfDeviceMap.put(did, device);
326 - providerService.deviceConnected(did, desc);
327 - log.info("Done with Device Info Creation on ONOS core. Device Info: "
328 - + device.deviceInfo() + " " + did.uri().toString());
329 - delay(EVENTINTERVAL);
330 - } catch (URISyntaxException e) {
331 - log.error("Syntax Error while creating URI for the device: "
332 - + device.deviceInfo()
333 - + " couldn't persist the device onto the store", e);
334 - } catch (SocketTimeoutException e) {
335 - log.error("Error while setting connection for the device: "
336 - + device.deviceInfo(), e);
337 - } catch (IOException e) {
338 - log.error("Error while setting connection for the device: "
339 - + device.deviceInfo(), e);
340 - } catch (Exception e) {
341 - log.error("Error while initializing session for the device: "
342 - + (device != null ? device.deviceInfo() : null), e);
343 - }
344 } 212 }
345 213
346 - /** 214 + @Override
347 - * This will build a device id for the device. 215 + public boolean isRelevant(NetworkConfigEvent event) {
348 - */ 216 + //TODO refactor
349 - private DeviceId getDeviceId() throws URISyntaxException { 217 + return event.configClass().equals(NetconfProviderConfig.class) &&
350 - String additionalSSP = new StringBuilder(device.getUsername()) 218 + (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
351 - .append("@").append(device.getSshHost()).append(":") 219 + event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED);
352 - .append(device.getSshPort()).toString();
353 - DeviceId did = DeviceId.deviceId(new URI(SCHEME, additionalSSP,
354 - null));
355 - return did;
356 } 220 }
357 } 221 }
358 } 222 }
......
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 +package org.onosproject.provider.netconf.device.impl;
18 +
19 +import com.fasterxml.jackson.databind.JsonNode;
20 +import com.google.common.annotations.Beta;
21 +import com.google.common.collect.Sets;
22 +import org.onlab.packet.IpAddress;
23 +import org.onosproject.core.ApplicationId;
24 +import org.onosproject.incubator.net.config.basics.ConfigException;
25 +import org.onosproject.net.config.Config;
26 +
27 +import java.util.Set;
28 +
29 +/**
30 + * Configuration for Netconf provider.
31 + */
32 +@Beta
33 +public class NetconfProviderConfig extends Config<ApplicationId> {
34 +
35 + public static final String CONFIG_VALUE_ERROR = "Error parsing config value";
36 + private static final String IP = "ip";
37 + private static final int DEFAULT_TCP_PORT = 830;
38 + private static final String PORT = "port";
39 + private static final String NAME = "name";
40 + private static final String PASSWORD = "password";
41 +
42 + public Set<NetconfDeviceAddress> getDevicesAddresses() throws ConfigException {
43 + Set<NetconfDeviceAddress> devicesAddresses = Sets.newHashSet();
44 +
45 + try {
46 + for (JsonNode node : array) {
47 + String ip = node.path(IP).asText();
48 + IpAddress ipAddr = ip.isEmpty() ? null : IpAddress.valueOf(ip);
49 + int port = node.path(PORT).asInt(DEFAULT_TCP_PORT);
50 + String name = node.path(NAME).asText();
51 + String password = node.path(PASSWORD).asText();
52 + devicesAddresses.add(new NetconfDeviceAddress(ipAddr, port, name, password));
53 +
54 + }
55 + } catch (IllegalArgumentException e) {
56 + throw new ConfigException(CONFIG_VALUE_ERROR, e);
57 + }
58 +
59 + return devicesAddresses;
60 + }
61 +
62 + public class NetconfDeviceAddress {
63 + private final IpAddress ip;
64 + private final int port;
65 + private final String name;
66 + private final String password;
67 +
68 + public NetconfDeviceAddress(IpAddress ip, int port, String name, String password) {
69 + this.ip = ip;
70 + this.port = port;
71 + this.name = name;
72 + this.password = password;
73 + }
74 +
75 + public IpAddress ip() {
76 + return ip;
77 + }
78 +
79 + public int port() {
80 + return port;
81 + }
82 +
83 + public String name() {
84 + return name;
85 + }
86 +
87 + public String password() {
88 + return password;
89 + }
90 + }
91 +
92 +
93 +}
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 org.easymock.EasyMock.expect;
19 -import static org.easymock.EasyMock.replay;
20 -import static org.junit.Assert.assertFalse;
21 -import static org.onlab.util.Tools.delay;
22 -import static org.onosproject.provider.netconf.device.impl.NetconfDeviceProviderTestConstant.*;
23 -import static org.slf4j.LoggerFactory.getLogger;
24 -
25 -import java.io.IOException;
26 -import java.net.URI;
27 -import java.net.URISyntaxException;
28 -import java.util.Collection;
29 -import java.util.Dictionary;
30 -import java.util.List;
31 -import java.util.Map;
32 -import java.util.Set;
33 -import java.util.concurrent.ConcurrentHashMap;
34 -
35 -import org.easymock.EasyMock;
36 -import org.junit.After;
37 -import org.junit.Before;
38 -import org.junit.Ignore;
39 -import org.junit.Test;
40 -import org.onlab.packet.ChassisId;
41 -import org.onosproject.cfg.ComponentConfigService;
42 -import org.onosproject.net.Device;
43 -import org.onosproject.net.DeviceId;
44 -import org.onosproject.net.MastershipRole;
45 -import org.onosproject.net.device.DefaultDeviceDescription;
46 -import org.onosproject.net.device.DeviceDescription;
47 -import org.onosproject.net.device.DeviceProvider;
48 -import org.onosproject.net.device.DeviceProviderRegistry;
49 -import org.onosproject.net.device.DeviceProviderService;
50 -import org.onosproject.net.device.PortDescription;
51 -import org.onosproject.net.device.PortStatistics;
52 -import org.onosproject.net.provider.ProviderId;
53 -import org.osgi.service.component.ComponentContext;
54 -import org.slf4j.Logger;
55 -
56 -import com.tailf.jnc.JNCException;
57 -
58 -/**
59 - * Test Case to Validate Netconf Device Provider.
60 - */
61 -public class NetconfDeviceProviderTest {
62 - TestDeviceCreator create;
63 -
64 - private final Logger log = getLogger(NetconfDeviceProviderTest.class);
65 -
66 - private Map<DeviceId, NetconfDevice> netconfDeviceMap = new ConcurrentHashMap<DeviceId, NetconfDevice>();
67 -
68 - private DeviceProviderService providerService;
69 -
70 - private static final DeviceId DID1 = DeviceId.deviceId(DEVICE_ID);
71 -
72 - private final NetconfDeviceProvider provider = new NetconfDeviceProvider();
73 - private final TestDeviceRegistry registry = new TestDeviceRegistry();
74 -
75 - private ComponentConfigService mockCfgService;
76 -
77 - @Before
78 - public void setUp() {
79 - mockCfgService = EasyMock.createMock(ComponentConfigService.class);
80 - provider.cfgService = mockCfgService;
81 - provider.providerRegistry = registry;
82 - }
83 -
84 - @SuppressWarnings("unchecked")
85 - private Dictionary<String, String> getDictionaryMockWithoutValues(ComponentContext componentContext) {
86 - Dictionary<String, String> dictionary = EasyMock
87 - .createMock(Dictionary.class);
88 - expect(dictionary.get(DEV_CONFIG)).andReturn(NULL);
89 - replay(dictionary);
90 - expect(componentContext.getProperties()).andReturn(dictionary);
91 - return dictionary;
92 - }
93 -
94 - @SuppressWarnings("unchecked")
95 - private Dictionary<String, String> getDictionaryMockWithDeviceEntryNull(ComponentContext componentContext) {
96 - Dictionary<String, String> dictionary = EasyMock
97 - .createMock(Dictionary.class);
98 - expect(dictionary.get(DEV_CONFIG)).andReturn(NULL_NULL);
99 - replay(dictionary);
100 - expect(componentContext.getProperties()).andReturn(dictionary);
101 - return dictionary;
102 - }
103 -
104 - @SuppressWarnings("unchecked")
105 - private Dictionary<String, String> getDictionaryMockDeviceEntryNumberFomatEx(ComponentContext componentContext) {
106 - Dictionary<String, String> dictionary = EasyMock
107 - .createMock(Dictionary.class);
108 - expect(dictionary.get(DEV_CONFIG))
109 - .andReturn(CONFIG_WITH_INVALID_ENTRY_NUMBER)
110 - .andThrow(new NumberFormatException());
111 - replay(dictionary);
112 - expect(componentContext.getProperties()).andReturn(dictionary);
113 - return dictionary;
114 - }
115 -
116 - @SuppressWarnings("unchecked")
117 - private Dictionary<String, String> getDictionaryMockWithoutUsernameAndPassword(ComponentContext componentContext) {
118 - Dictionary<String, String> dictionary = EasyMock
119 - .createMock(Dictionary.class);
120 - expect(dictionary.get(DEV_CONFIG)).andReturn(CONFIG_WITH_NULL_ENTRY);
121 - replay(dictionary);
122 - expect(componentContext.getProperties()).andReturn(dictionary);
123 - return dictionary;
124 - }
125 -
126 - @SuppressWarnings("unchecked")
127 - private Dictionary<String, String> getDictionaryMockWithDifferentDeviceState(ComponentContext componentContext) {
128 - Dictionary<String, String> dictionary = EasyMock
129 - .createMock(Dictionary.class);
130 - expect(dictionary.get(DEV_CONFIG))
131 - .andReturn(CONFIG_WITH_DIFFERENT_DEVICE_STATE);
132 - replay(dictionary);
133 - expect(componentContext.getProperties()).andReturn(dictionary);
134 - return dictionary;
135 - }
136 -
137 - @SuppressWarnings("unchecked")
138 - private Dictionary<String, String> getDictionaryMockDeviceWithArrayOutOFBoundEx(ComponentContext componentContext) {
139 - Dictionary<String, String> dictionary = EasyMock
140 - .createMock(Dictionary.class);
141 - expect(dictionary.get(DEV_CONFIG))
142 - .andReturn(CONFIG_WITH_ARRAY_OUT_OF_BOUNDEX)
143 - .andThrow(new ArrayIndexOutOfBoundsException());
144 - replay(dictionary);
145 - expect(componentContext.getProperties()).andReturn(dictionary);
146 - return dictionary;
147 - }
148 -
149 - @SuppressWarnings("unchecked")
150 - private Dictionary<String, String> getDictionaryMockDeviceEntryForDeactivate(ComponentContext componentContext) {
151 - Dictionary<String, String> dictionary = EasyMock
152 - .createMock(Dictionary.class);
153 - expect(dictionary.get(DEV_CONFIG))
154 - .andReturn(CONFIG_ENTRY_FOR_DEACTIVATE)
155 - .andThrow(new ArrayIndexOutOfBoundsException());
156 - replay(dictionary);
157 - expect(componentContext.getProperties()).andReturn(dictionary);
158 - return dictionary;
159 - }
160 -
161 - @Ignore
162 - @Test(expected = IOException.class)
163 - public void testSSHAuthentication() throws IOException, JNCException {
164 - TestDeviceCreator objForTestDev = new TestDeviceCreator(
165 - new NetconfDevice(
166 - DEVICE_IP,
167 - DEVICE_PORT,
168 - DEVICE_USERNAME,
169 - DEVICE_PASSWORD),
170 - true);
171 - objForTestDev.run();
172 - }
173 -
174 - @After
175 - public void tearDown() {
176 - provider.providerRegistry = null;
177 - provider.cfgService = null;
178 - }
179 -
180 - // To check if deviceCfgValue is empty or null
181 - @Test
182 - public void testActiveWithcomponentContextIsNull() {
183 -
184 - ComponentContext componentContext = EasyMock
185 - .createMock(ComponentContext.class);
186 - getDictionaryMockWithoutValues(componentContext);
187 - replay(componentContext);
188 - provider.activate(componentContext);
189 - }
190 -
191 - // To check deviceEntry and device is null
192 - @Test
193 - public void testActiveWithDeviceEntryIsNull() {
194 -
195 - ComponentContext componentContext = EasyMock
196 - .createMock(ComponentContext.class);
197 - getDictionaryMockWithDeviceEntryNull(componentContext);
198 - replay(componentContext);
199 - provider.activate(componentContext);
200 - }
201 -
202 - @Test
203 - public void testActiveWithDeviceEntryWithoutUsernameAndPassword() {
204 -
205 - ComponentContext componentContext = EasyMock
206 - .createMock(ComponentContext.class);
207 - getDictionaryMockWithoutUsernameAndPassword(componentContext);
208 - replay(componentContext);
209 - provider.activate(componentContext);
210 - }
211 -
212 - @Test
213 - public void testActiveWithDeviceEntryWithNumberFomatEx() {
214 -
215 - ComponentContext componentContext = EasyMock
216 - .createMock(ComponentContext.class);
217 - getDictionaryMockDeviceEntryNumberFomatEx(componentContext);
218 - replay(componentContext);
219 - provider.activate(componentContext);
220 - }
221 -
222 - @Test
223 - public void testActiveWithDeviceEntryWithDifferentDeviceState() {
224 -
225 - ComponentContext componentContext = EasyMock
226 - .createMock(ComponentContext.class);
227 - getDictionaryMockWithDifferentDeviceState(componentContext);
228 - replay(componentContext);
229 - provider.activate(componentContext);
230 - }
231 -
232 - @Test
233 - public void testActiveWithDeviceEntryWithArrayOutOFBoundEx() {
234 -
235 - ComponentContext componentContext = EasyMock
236 - .createMock(ComponentContext.class);
237 - getDictionaryMockDeviceWithArrayOutOFBoundEx(componentContext);
238 - replay(componentContext);
239 - provider.activate(componentContext);
240 - }
241 -
242 - @Test
243 - public void isReachableWithInvalidDeviceId() {
244 - assertFalse("Initially the Device ID Should not be reachable",
245 - provider.isReachable(DID1));
246 - NetconfDevice device = new NetconfDevice(NULL, ZERO, NULL, NULL);
247 - provider.netconfDeviceMap.put(DID1, device);
248 - assertFalse("Particular Device ID cannot be Reachable",
249 - provider.isReachable(DID1));
250 - }
251 -
252 - @Test
253 - public void testDeactivate() {
254 -
255 - ComponentContext componentContext = EasyMock
256 - .createMock(ComponentContext.class);
257 - getDictionaryMockDeviceEntryForDeactivate(componentContext);
258 - replay(componentContext);
259 - testActiveWithDeviceEntryWithDifferentDeviceState();
260 - provider.deactivate(componentContext);
261 - }
262 -
263 - private class TestDeviceCreator {
264 -
265 - private NetconfDevice device;
266 - private boolean createFlag;
267 -
268 - public TestDeviceCreator(NetconfDevice device, boolean createFlag) {
269 - this.device = device;
270 - this.createFlag = createFlag;
271 - }
272 -
273 - public void run() throws JNCException, IOException {
274 - if (createFlag) {
275 - log.info("Trying to create Device Info on ONOS core");
276 - advertiseDevices();
277 - } else {
278 - log.info("Trying to remove Device Info on ONOS core");
279 - removeDevices();
280 - }
281 - }
282 -
283 - /**
284 - * For each Netconf Device, remove the entry from the device store.
285 - */
286 - private void removeDevices() {
287 - if (device == null) {
288 - log.warn("The Request Netconf Device is null, cannot proceed further");
289 - return;
290 - }
291 - try {
292 - DeviceId did = getDeviceId();
293 - if (!netconfDeviceMap.containsKey(did)) {
294 - log.error("BAD Request: 'Currently device is not discovered, "
295 - + "so cannot remove/disconnect the device: "
296 - + device.deviceInfo() + "'");
297 - return;
298 - }
299 - providerService.deviceDisconnected(did);
300 - device.disconnect();
301 - netconfDeviceMap.remove(did);
302 - delay(EVENTINTERVAL);
303 - } catch (URISyntaxException uriSyntaxExcpetion) {
304 - log.error("Syntax Error while creating URI for the device: "
305 - + device.deviceInfo()
306 - + " couldn't remove the device from the store",
307 - uriSyntaxExcpetion);
308 - }
309 - }
310 -
311 - /**
312 - * Initialize Netconf Device object, and notify core saying device
313 - * connected.
314 - */
315 - private void advertiseDevices() throws JNCException, IOException {
316 - try {
317 - if (device == null) {
318 - log.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 - NULL,
328 - NULL,
329 - NULL,
330 - NULL, cid);
331 - log.info("Persisting Device" + did.uri().toString());
332 -
333 - netconfDeviceMap.put(did, device);
334 - providerService.deviceConnected(did, desc);
335 - log.info("Done with Device Info Creation on ONOS core. Device Info: "
336 - + device.deviceInfo() + " " + did.uri().toString());
337 - delay(EVENTINTERVAL);
338 - } catch (URISyntaxException e) {
339 - log.error("Syntax Error while creating URI for the device: "
340 - + device.deviceInfo()
341 - + " couldn't persist the device onto the store", e);
342 - } catch (JNCException e) {
343 - throw e;
344 - } catch (IOException e) {
345 - throw e;
346 - } catch (Exception e) {
347 - log.error("Error while initializing session for the device: "
348 - + device.deviceInfo(), e);
349 - }
350 - }
351 -
352 - private DeviceId getDeviceId() throws URISyntaxException {
353 - String additionalSSP = new StringBuilder(device.getUsername())
354 - .append(AT_THE_RATE).append(device.getSshHost())
355 - .append(COLON).append(device.getSshPort()).toString();
356 - DeviceId did = DeviceId.deviceId(new URI(SCHEME_NETCONF,
357 - additionalSSP, null));
358 - return did;
359 - }
360 - }
361 -
362 - private class TestDeviceRegistry implements DeviceProviderRegistry {
363 -
364 - @Override
365 - public DeviceProviderService register(DeviceProvider provider) {
366 - return new TestProviderService();
367 - }
368 -
369 - @Override
370 - public void unregister(DeviceProvider provider) {
371 - }
372 -
373 - @Override
374 - public Set<ProviderId> getProviders() {
375 - return null;
376 - }
377 -
378 - private class TestProviderService implements DeviceProviderService {
379 -
380 - @Override
381 - public DeviceProvider provider() {
382 - return null;
383 - }
384 -
385 - @Override
386 - public void deviceConnected(DeviceId deviceId,
387 - DeviceDescription deviceDescription) {
388 - }
389 -
390 - @Override
391 - public void deviceDisconnected(DeviceId deviceId) {
392 -
393 - }
394 -
395 - @Override
396 - public void updatePorts(DeviceId deviceId,
397 - List<PortDescription> portDescriptions) {
398 -
399 - }
400 -
401 - @Override
402 - public void portStatusChanged(DeviceId deviceId,
403 - PortDescription portDescription) {
404 -
405 - }
406 -
407 - @Override
408 - public void receivedRoleReply(DeviceId deviceId,
409 - MastershipRole requested,
410 - MastershipRole response) {
411 -
412 - }
413 -
414 - @Override
415 - public void updatePortStatistics(DeviceId deviceId,
416 - Collection<PortStatistics> portStatistics) {
417 -
418 - }
419 - }
420 - }
421 -}
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 -public final class NetconfDeviceProviderTestConstant {
19 -
20 - private NetconfDeviceProviderTestConstant() {
21 - }
22 -
23 - public static final int ZERO = 0;
24 - public static final int EVENTINTERVAL = 5;
25 - public static final String DEV_CONFIG = "devConfigs";
26 - public static final String CONFIG_WITH_INVALID_ENTRY_NUMBER = "cisco:cisco"
27 - + "@10.18.11.14:cisco:active";
28 - public static final String CONFIG_WITH_NULL_ENTRY = "null:null@null:0:active";
29 - public static final String CONFIG_WITH_DIFFERENT_DEVICE_STATE = "cisco:cisco@10.18.11.14:22:active,"
30 - + "cisco:cisco@10.18.11.18:22:inactive,cisco:cisco@10.18.11.14:22:invalid,"
31 - + "cisco:cisco@10.18.11.14:22:null";
32 - public static final String CONFIG_WITH_ARRAY_OUT_OF_BOUNDEX = "@10.18.11.14:22:active";
33 - public static final String CONFIG_ENTRY_FOR_DEACTIVATE = "netconf:cisco"
34 - + "@10.18.11.14:22:active";
35 - public static final String DEVICE_IP = "10.18.14.19";
36 - public static final int DEVICE_PORT = 22;
37 - public static final String DEVICE_USERNAME = "cisco";
38 - public static final String DEVICE_PASSWORD = "cisco";
39 - public static final String AT_THE_RATE = "@";
40 - public static final String COLON = ":";
41 - public static final String NULL = "";
42 - public static final String NULL_NULL = "null,null";
43 - public static final String SCHEME_NETCONF = "netconf";
44 - public static final String DEVICE_ID = "of:0000000000000001";
45 -
46 -}
1 +{
2 + "devices":{
3 + "netconf:mininet@10.1.9.24:1830":{
4 + "basic":{
5 + "driver":"ovs-netconf"
6 + }
7 + }
8 + },
9 + "apps":{
10 + "org.onosproject.netconf":{
11 + "devices":[{
12 + "name":"mininet",
13 + "password":"mininet",
14 + "ip":"10.1.9.24",
15 + "port":1830
16 + }]
17 + }
18 + }
19 +}
...\ No newline at end of file ...\ No newline at end of file