[ONOS-4747] NETCONF function for FUJITSU OLT #2
- Enhanced device-setcontrollers command to apply additional key-value pair.
e.g. onos> device-setcontrollers netconf:10.10.1.11:830 tcp:10.10.1.11:6630,ofconfig-id=1
Change-Id: I2cb5941dbd9829ade6fa89d5546bbc6aab44f83f
diff --git a/cli/src/main/java/org/onosproject/cli/net/DeviceSetControllersCommand.java b/cli/src/main/java/org/onosproject/cli/net/DeviceSetControllersCommand.java
index 556dcc9..5d0707d 100644
--- a/cli/src/main/java/org/onosproject/cli/net/DeviceSetControllersCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/DeviceSetControllersCommand.java
@@ -18,7 +18,10 @@
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.IpAddress;
import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.Annotations;
+import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DeviceId;
import org.onosproject.net.behaviour.ControllerConfig;
import org.onosproject.net.behaviour.ControllerInfo;
@@ -52,7 +55,7 @@
protected void execute() {
Arrays.asList(controllersListStrings).forEach(
- cInfoString -> newControllers.add(new ControllerInfo(cInfoString)));
+ cInfoString -> newControllers.add(parseCInfoString(cInfoString)));
DriverService service = get(DriverService.class);
deviceId = DeviceId.deviceId(uri);
DriverHandler h = service.createHandler(deviceId);
@@ -69,4 +72,31 @@
print("size %d", config.getControllers().size());
}
+
+ private ControllerInfo parseCInfoString(String cInfoString) {
+ Annotations annotation;
+
+ String[] config = cInfoString.split(",");
+ if (config.length == 2) {
+ String[] pair = config[1].split("=");
+
+ if (pair.length == 2) {
+ annotation = DefaultAnnotations.builder()
+ .set(pair[0], pair[1]).build();
+ } else {
+ print("Wrong format {}", config[1]);
+ return null;
+ }
+
+ String[] data = config[0].split(":");
+ String type = data[0];
+ IpAddress ip = IpAddress.valueOf(data[1]);
+ int port = Integer.parseInt(data[2]);
+
+ return new ControllerInfo(ip, port, type, annotation);
+ } else {
+ print(config[0]);
+ return new ControllerInfo(config[0]);
+ }
+ }
}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java b/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java
index 98f2599..cc965b1 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java
@@ -17,17 +17,23 @@
import com.google.common.base.Preconditions;
import org.onlab.packet.IpAddress;
+import org.onosproject.net.Annotated;
+import org.onosproject.net.Annotations;
+import org.onosproject.net.DefaultAnnotations;
+
+import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Objects;
/**
* Represents information for a device to connect to a controller.
*/
-public class ControllerInfo {
+public class ControllerInfo implements Annotated {
private IpAddress ip = IpAddress.valueOf("0.0.0.0");
private int port = 6653;
private String type = "error";
+ private final Annotations annotations;
/**
* Information for contacting the controller.
@@ -37,18 +43,36 @@
* @param type the connection type
*/
public ControllerInfo(IpAddress ip, int port, String type) {
- this.ip = ip;
- this.port = port;
- this.type = type;
+ this(ip, port, type, DefaultAnnotations.EMPTY);
}
/**
+ * Information for contacting the controller.
+ *
+ * @param ip the ip address
+ * @param port the tcp port
+ * @param type the connection type
+ * @param annotations optional key/value annotations
+ */
+ public ControllerInfo(IpAddress ip, int port, String type, Annotations annotations) {
+ this.ip = checkNotNull(ip);
+ this.port = port;
+ this.type = checkNotNull(type);
+ this.annotations = checkNotNull(annotations);
+ }
+
+ // TODO Factory method equivalent to this method
+ // should probably live in OVSDB, NETCONF package.
+ /**
* Information for contacting the controller, if some information
* is not contained in the target string because it's optional
* it's leaved as in the field declaration (default values).
*
* @param target column returned from ovsdb query
+ *
+ * @deprecated in Hummingbird (1.7.0)
*/
+ @Deprecated
public ControllerInfo(String target) {
String[] data = target.split(":");
this.type = data[0];
@@ -69,6 +93,7 @@
this.port = Integer.parseInt(data[2]);
}
}
+ this.annotations = DefaultAnnotations.EMPTY;
}
/**
@@ -98,11 +123,24 @@
return type;
}
+ @Override
+ public Annotations annotations() {
+ return annotations;
+ }
+
+ // TODO Method equivalent to this method
+ // should probably live in OVSDB, NETCONF package.
+ // @deprecated in Hummingbird (1.7.0)
+ @Deprecated
public String target() {
if (type.startsWith("p")) {
return type + ":" + port + ":" + ip;
} else {
- return type + ":" + ip + ":" + port;
+ if (annotations.equals(DefaultAnnotations.EMPTY)) {
+ return type + ":" + ip + ":" + port;
+ } else {
+ return type + ":" + ip + ":" + port + ":" + annotations.toString();
+ }
}
}
@@ -115,12 +153,10 @@
@Override
public boolean equals(Object toBeCompared) {
if (toBeCompared instanceof ControllerInfo) {
- ControllerInfo controllerInfo = (ControllerInfo) toBeCompared;
- if (controllerInfo.type().equals(this.type)
- && controllerInfo.ip().equals(this.ip())
- && controllerInfo.port() == this.port) {
- return true;
- }
+ ControllerInfo that = (ControllerInfo) toBeCompared;
+ return Objects.equals(this.type, that.type) &&
+ Objects.equals(this.ip, that.ip) &&
+ Objects.equals(this.port, that.port);
}
return false;
}
diff --git a/drivers/fujitsu/src/main/java/org/onosproject/drivers/fujitsu/FujitsuVoltControllerConfig.java b/drivers/fujitsu/src/main/java/org/onosproject/drivers/fujitsu/FujitsuVoltControllerConfig.java
index b61916e..f06ad81 100644
--- a/drivers/fujitsu/src/main/java/org/onosproject/drivers/fujitsu/FujitsuVoltControllerConfig.java
+++ b/drivers/fujitsu/src/main/java/org/onosproject/drivers/fujitsu/FujitsuVoltControllerConfig.java
@@ -19,18 +19,26 @@
import com.google.common.collect.ImmutableList;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.onosproject.drivers.utilities.XmlConfigParser;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.commons.configuration.tree.ConfigurationNode;
import org.onlab.packet.IpAddress;
import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.Annotations;
+import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.DeviceId;
import org.onosproject.net.behaviour.ControllerConfig;
import org.onosproject.net.behaviour.ControllerInfo;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.net.driver.DriverHandler;
import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfDevice;
+import org.onosproject.netconf.NetconfException;
import org.slf4j.Logger;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@@ -46,8 +54,11 @@
implements ControllerConfig {
private final Logger log = getLogger(FujitsuVoltControllerConfig.class);
+ private static final String RESOURCE_XML = "voltcontrollers.xml";
private static final String DOT = ".";
+ private static final String L_ANGLE_BR = "<";
+ private static final String R_ANGLE_BR = "/>";
private static final String VOLT_NE_NAMESPACE =
"xmlns=\"http://fujitsu.com/ns/volt/1.1\"";
private static final String DATA = "data";
@@ -60,14 +71,35 @@
private static final String IP_ADDRESS = "ip-address";
private static final String PORT = "port";
private static final String PROTOCOL = "protocol";
+ private static final String CONFIG = "config";
+ private static final String OFCONFIG_ID = "ofconfig-id";
+ private static final String EDIT_CONFIG = "edit-config";
+ private static final String TARGET = "target";
+ private static final String RUNNING = "running";
+ private static final String MERGE = "merge";
+ private static final String DEFAULT_OPERATION = "default-operation";
private static final String VOLT_NE_OPEN = "<" + VOLT_NE + " ";
private static final String VOLT_NE_CLOSE = "</" + VOLT_NE + ">";
private static final String VOLT_OFCONFIG_EL = "<" + VOLT_OFCONFIG + "/>\n";
+ private static final String TARGET_OPEN = "<" + TARGET + ">";
+ private static final String TARGET_CLOSE = "</" + TARGET + ">";
+ private static final String END_LICENSE_HEADER = "-->";
private static final String VOLT_DATACONFIG = DATA + DOT + VOLT_NE + DOT +
VOLT_OFCONFIG + DOT + OF_CONTROLLERS + DOT + OF_CONTROLLER;
+ private static final String EDIT_CONFIG_TG = EDIT_CONFIG + DOT + TARGET;
+ private static final String EDIT_CONFIG_DO = EDIT_CONFIG + DOT + DEFAULT_OPERATION;
+ private static final String CONTROLLER_INFO_ID = CONTROLLER_INFO + DOT + "id";
+ private static final String CONTROLLER_INFO_IP = CONTROLLER_INFO + DOT + IP_ADDRESS;
+ private static final String CONTROLLER_INFO_PORT = CONTROLLER_INFO + DOT + PORT;
+ private static final String CONTROLLER_INFO_PROTOCOL = CONTROLLER_INFO + DOT + PROTOCOL;
+
+ private static final String VOLT_EDITCONFIG = EDIT_CONFIG + DOT +
+ CONFIG + DOT + VOLT_NE + DOT + VOLT_OFCONFIG + DOT + OF_CONTROLLERS;
+
+
@Override
public List<ControllerInfo> getControllers() {
DriverHandler handler = handler();
@@ -85,11 +117,11 @@
String reply;
reply = controller.
- getDevicesMap().get(ncDeviceId).getSession().
- get(request.toString(), REPORT_ALL);
+ getDevicesMap().get(ncDeviceId).getSession().
+ get(request.toString(), REPORT_ALL);
log.debug("Reply XML {}", reply);
controllers.addAll(parseStreamVoltControllers(XmlConfigParser.
- loadXml(new ByteArrayInputStream(reply.getBytes(StandardCharsets.UTF_8)))));
+ loadXml(new ByteArrayInputStream(reply.getBytes(StandardCharsets.UTF_8)))));
} catch (IOException e) {
log.error("Cannot communicate to device {} ", ncDeviceId);
}
@@ -103,10 +135,31 @@
@Override
public void setControllers(List<ControllerInfo> controllers) {
- // TODO update later
- log.warn("Operation not supported");
+ DriverHandler handler = handler();
+ NetconfController controller = handler.get(NetconfController.class);
+ MastershipService mastershipService = handler.get(MastershipService.class);
+ DeviceId ncdeviceId = handler.data().deviceId();
+ checkNotNull(controller, "Netconf controller is null");
+ if (mastershipService.isLocalMaster(ncdeviceId)) {
+ try {
+ NetconfDevice device = controller.getNetconfDevice(ncdeviceId);
+ String config = createVoltControllersConfig(
+ XmlConfigParser.loadXml(getClass().
+ getResourceAsStream(RESOURCE_XML)),
+ RUNNING, MERGE, controllers);
+ device.getSession().editConfig(config.substring(
+ config.indexOf(END_LICENSE_HEADER) + END_LICENSE_HEADER.length()));
+ } catch (NetconfException e) {
+ log.error("Cannot communicate to device {} , exception ", ncdeviceId, e);
+ }
+ } else {
+ log.warn("I'm not master for {} please use master, {} to execute command",
+ ncdeviceId,
+ mastershipService.getMasterFor(ncdeviceId));
+ }
}
+
/**
* Parses XML string to get controller information.
*
@@ -123,17 +176,67 @@
sub.configurationsAt(CONTROLLER_INFO);
for (HierarchicalConfiguration child : childFields) {
+ Annotations annotations = DefaultAnnotations.builder()
+ .set(OFCONFIG_ID, sub.getString(OFCONFIG_ID)).build();
ControllerInfo controller = new ControllerInfo(
IpAddress.valueOf(child.getString(IP_ADDRESS)),
Integer.parseInt(child.getString(PORT)),
- child.getString(PROTOCOL));
+ child.getString(PROTOCOL), annotations);
- log.debug("VOLT: OFCONTROLLER: PROTOCOL={}, IP={}, PORT={} ",
- controller.type(), controller.ip(), controller.port());
+ log.debug("VOLT: OFCONTROLLER: PROTOCOL={}, IP={}, PORT={}, ID={} ",
+ controller.type(), controller.ip(),
+ controller.port(), controller.annotations().value(OFCONFIG_ID));
controllers.add(controller);
}
}
return controllers;
}
+ /**
+ * Forms XML string to change controller information.
+ *
+ * @param cfg a hierarchical configuration
+ * @param target the type of configuration
+ * @param netconfOperation operation type
+ * @param controllers list of controllers
+ * @return XML string
+ */
+ public static String createVoltControllersConfig(HierarchicalConfiguration cfg,
+ String target, String netconfOperation,
+ List<ControllerInfo> controllers) {
+ XMLConfiguration editcfg = null;
+
+ cfg.setProperty(EDIT_CONFIG_TG, target);
+ cfg.setProperty(EDIT_CONFIG_DO, netconfOperation);
+
+ List<ConfigurationNode> newControllers = new ArrayList<>();
+ for (ControllerInfo ci : controllers) {
+ XMLConfiguration controller = new XMLConfiguration();
+ controller.setRoot(new HierarchicalConfiguration.Node(OF_CONTROLLER));
+ controller.setProperty(OFCONFIG_ID, ci.annotations().value(OFCONFIG_ID));
+ controller.setProperty(CONTROLLER_INFO_ID, ci.annotations().value(OFCONFIG_ID));
+ controller.setProperty(CONTROLLER_INFO_IP, ci.ip());
+ controller.setProperty(CONTROLLER_INFO_PORT, ci.port());
+ controller.setProperty(CONTROLLER_INFO_PROTOCOL, ci.type());
+ newControllers.add(controller.getRootNode());
+ }
+ cfg.addNodes(VOLT_EDITCONFIG, newControllers);
+
+ try {
+ editcfg = (XMLConfiguration) cfg;
+ } catch (ClassCastException e) {
+ e.printStackTrace();
+ }
+ StringWriter stringWriter = new StringWriter();
+ try {
+ editcfg.save(stringWriter);
+ } catch (ConfigurationException e) {
+ e.printStackTrace();
+ }
+ String s = stringWriter.toString();
+ s = s.replace(TARGET_OPEN + target + TARGET_CLOSE,
+ TARGET_OPEN + L_ANGLE_BR + target + R_ANGLE_BR + TARGET_CLOSE);
+ return s;
+ }
+
}
diff --git a/drivers/fujitsu/src/main/resources/org/onosproject/drivers/fujitsu/voltcontrollers.xml b/drivers/fujitsu/src/main/resources/org/onosproject/drivers/fujitsu/voltcontrollers.xml
new file mode 100644
index 0000000..5403a35
--- /dev/null
+++ b/drivers/fujitsu/src/main/resources/org/onosproject/drivers/fujitsu/voltcontrollers.xml
@@ -0,0 +1,32 @@
+<!--
+ ~ Copyright 2016-present Open Networking Laboratory
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <edit-config>
+ <target>
+ </target>
+ <default-operation>
+ </default-operation>
+ <config>
+ <volt-ne xmlns="http://fujitsu.com/ns/volt/1.1">
+ <volt-ofconfig>
+ <of-controllers>
+ </of-controllers>
+ </volt-ofconfig>
+ </volt-ne>
+ </config>
+ </edit-config>
+</rpc>