ODTN manual testing tool for OpenConfig configuration
- ONOS-7567
Example:
onos> odtn-manual-test ENABLE_TRANSCEIVER
JSON:
{
"openconfig-platform:component" : [ {
"name" : "TRANSCEIVER_1_1_4_1",
"openconfig-platform-transceiver:transceiver" : {
"config" : {
"enabled" : "true"
}
},
"config" : {
"name" : "TRANSCEIVER_1_1_4_1"
}
} ]
}
XML:
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<edit-config>
<target>
<running/>
</target>
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<component xmlns="http://openconfig.net/yang/platform" xc:operation="merge">
<name>TRANSCEIVER_1_1_4_1</name>
<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
<config>
<enabled>true</enabled>
</config>
</transceiver>
<config>
<name>TRANSCEIVER_1_1_4_1</name>
</config>
</component>
</config>
</edit-config>
</rpc>
Change-Id: Ief5f1a1933fb00a2118bd941d8c5f0310ed9c815
diff --git a/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/ModeCompleter.java b/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/ModeCompleter.java
new file mode 100644
index 0000000..f00a3f8
--- /dev/null
+++ b/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/ModeCompleter.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.odtn.cli.impl;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+import org.onosproject.cli.AbstractChoicesCompleter;
+import org.onosproject.odtn.cli.impl.OdtnManualTestCommand.Mode;
+
+public class ModeCompleter extends AbstractChoicesCompleter {
+
+ @Override
+ protected List<String> choices() {
+ return Arrays.asList(Mode.values())
+ .stream()
+ .map(Enum::name)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/OdtnManualTestCommand.java b/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/OdtnManualTestCommand.java
new file mode 100644
index 0000000..4f1ed4a
--- /dev/null
+++ b/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/OdtnManualTestCommand.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.odtn.cli.impl;
+
+import static org.onosproject.odtn.utils.YangToolUtil.toCharSequence;
+import static org.onosproject.odtn.utils.YangToolUtil.toCompositeData;
+import static org.onosproject.odtn.utils.YangToolUtil.toDocument;
+import static org.onosproject.odtn.utils.YangToolUtil.toJsonCompositeStream;
+import static org.onosproject.odtn.utils.YangToolUtil.toJsonNode;
+import static org.onosproject.odtn.utils.YangToolUtil.toResourceData;
+import static org.onosproject.odtn.utils.YangToolUtil.toXmlCompositeStream;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.regex.Pattern;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+import org.onlab.util.XmlString;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.cli.net.DeviceIdCompleter;
+import org.onosproject.config.DynamicConfigService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.netconf.NetconfController;
+import org.onosproject.netconf.NetconfDevice;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.odtn.cli.impl.sub.OpticalChannel;
+import org.onosproject.odtn.cli.impl.sub.Transceiver;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.ResourceId;
+import org.slf4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+
+
+@Command(scope = "onos", name = "odtn-manual-test",
+ description = "ODTN manual test command")
+public class OdtnManualTestCommand extends AbstractShellCommand {
+
+ private static final Logger log = getLogger(OdtnManualTestCommand.class);
+
+ public static enum Mode {
+ ENABLE_TRANSCEIVER,
+ DISABLE_TRANSCEIVER,
+ PRECONF_TRANSCEIVER,
+ PRECONF_OPTICAL_CHANNEL,
+ }
+
+ ModeCompleter modeCompleter;
+ @Argument(index = 0, name = "mode", description = "one of Mode see source",
+ required = true)
+ String modeStr = Mode.ENABLE_TRANSCEIVER.name();
+ Mode mode;
+
+ // injecting dependency for OSGi package import generation purpose
+ DeviceIdCompleter uriCompleter;
+ @Option(name = "--deviceId", description = "Device ID URI to send configuration to",
+ required = false)
+ String uri = null;
+
+ // TODO add completer for this?
+ @Option(name = "--component",
+ description = "Component name",
+ required = false, multiValued = false)
+ private String componentName = "TRANSCEIVER_1_1_4_1";
+
+
+ // OSGi Services to be filled in at the beginning.
+ private DynamicConfigService dcs;
+
+
+ void printlog(String format, Object... objs) {
+ print(format.replaceAll(Pattern.quote("{}"), "%s"), objs);
+ log.info(format, objs);
+ }
+
+ @Override
+ protected void execute() {
+ dcs = get(DynamicConfigService.class);
+
+ try {
+ mode = Mode.valueOf(modeStr);
+ } catch (IllegalArgumentException e) {
+ printlog("{} is not a valid Mode, pick one of {}",
+ modeStr,
+ Arrays.asList(Mode.values()),
+ e);
+ return;
+ }
+
+ // effectively configuration context
+ List<DataNode> nodes = new ArrayList<>();
+
+ switch (mode) {
+ case PRECONF_TRANSCEIVER:
+ nodes.addAll(Transceiver.preconf(componentName));
+ break;
+
+ case ENABLE_TRANSCEIVER:
+ nodes.addAll(Transceiver.enable(componentName, true));
+ break;
+
+ case DISABLE_TRANSCEIVER:
+ nodes.addAll(Transceiver.enable(componentName, false));
+ break;
+
+ case PRECONF_OPTICAL_CHANNEL:
+ nodes.addAll(OpticalChannel.preconf(componentName));
+ break;
+
+ default:
+ printlog("Mode {} not supported yet", mode);
+ break;
+ }
+
+ // Do something about it.
+ doTheMagic(nodes);
+ }
+
+ void doTheMagic(List<DataNode> nodes) {
+
+ Document doc;
+ try {
+ doc = DocumentBuilderFactory.newInstance()
+ .newDocumentBuilder().newDocument();
+ } catch (ParserConfigurationException e) {
+ printlog("Unexpected error", e);
+ throw new RuntimeException(e);
+ }
+
+ // netconf rpc boilerplate part without message-id
+ Element rpc = doc.createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0", "rpc");
+ doc.appendChild(rpc);
+ Element editConfig = doc.createElement("edit-config");
+ rpc.appendChild(editConfig);
+ Element target = doc.createElement("target");
+ editConfig.appendChild(target);
+ target.appendChild(doc.createElement("running"));
+
+ Element config = doc.createElement("config");
+ config.setAttributeNS("http://www.w3.org/2000/xmlns/",
+ "xmlns:xc",
+ "urn:ietf:params:xml:ns:netconf:base:1.0");
+ editConfig.appendChild(config);
+
+
+ for (DataNode node : nodes) {
+ // empty resourceId assuming node is root of cfg tree
+ ResourceId resourceId = ResourceId.builder().build();
+ Document ldoc = toDocument(toXmlCompositeStream(toCompositeData(toResourceData(resourceId, node))));
+ Element cfgRoot = ldoc.getDocumentElement();
+
+ // is everything as merge, ok?
+ cfgRoot.setAttribute("xc:operation", "merge");
+
+ // move (or copy) node to another Document
+ config.appendChild(Optional.ofNullable(doc.adoptNode(cfgRoot))
+ .orElseGet(() -> doc.importNode(cfgRoot, true)));
+
+ // don't have good use for JSON for now
+ JsonNode json = toJsonNode(toJsonCompositeStream(toCompositeData(toResourceData(resourceId, node))));
+ printlog("JSON:\n{}", toCharSequence(json));
+ }
+
+ printlog("XML:\n{}", XmlString.prettifyXml(toCharSequence(doc)));
+
+ // TODO if deviceId is given send it out to the device
+ if (uri != null) {
+ DeviceId deviceId = DeviceId.deviceId(uri);
+ NetconfController ctr = get(NetconfController.class);
+ Optional.ofNullable(ctr.getNetconfDevice(deviceId))
+ .map(NetconfDevice::getSession)
+ .ifPresent(session -> {
+ try {
+ session.rpc(toCharSequence(doc, false).toString()).join();
+ } catch (NetconfException e) {
+ log.error("Exception thrown", e);
+ }
+ });
+ }
+ }
+}
diff --git a/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/package-info.java b/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/package-info.java
new file mode 100644
index 0000000..9799fab
--- /dev/null
+++ b/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.
+ */
+/**
+ * ODTN CLI commands implementations.
+ */
+package org.onosproject.odtn.cli.impl;
diff --git a/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/sub/OpticalChannel.java b/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/sub/OpticalChannel.java
new file mode 100644
index 0000000..9d813e5
--- /dev/null
+++ b/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/sub/OpticalChannel.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.odtn.cli.impl.sub;
+
+import static org.onosproject.odtn.utils.YangToolUtil.toDataNode;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.List;
+
+import org.onosproject.yang.gen.v1.openconfigplatform.rev20161222.openconfigplatform.platformcomponenttop.DefaultComponents;
+import org.onosproject.yang.gen.v1.openconfigplatform.rev20161222.openconfigplatform.platformcomponenttop.components.Component;
+import org.onosproject.yang.gen.v1.openconfigterminaldevice.rev20170708.openconfigterminaldevice.components.component.DefaultAugmentedOcPlatformComponent;
+import org.onosproject.yang.gen.v1.openconfigterminaldevice.rev20170708.openconfigterminaldevice.terminalopticalchanneltop.DefaultOpticalChannel;
+import org.onosproject.yang.gen.v1.openconfigterminaldevice.rev20170708.openconfigterminaldevice.terminalopticalchanneltop.opticalchannel.Config;
+import org.onosproject.yang.gen.v1.openconfigterminaldevice.rev20170708.openconfigterminaldevice.terminalopticalchanneltop.opticalchannel.DefaultConfig;
+import org.onosproject.yang.gen.v1.openconfigtransporttypes.rev20170816.openconfigtransporttypes.FrequencyType;
+import org.onosproject.yang.model.DataNode;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Utility methods dealing with OpenConfig optical-channel.
+ * <p>
+ * Split into classes for the purpose of avoiding "Config" class collisions.
+ */
+@Beta
+public abstract class OpticalChannel {
+
+ public static List<DataNode> preconf(String componentName) {
+
+ DefaultComponents components = new DefaultComponents();
+
+ Component component = PlainPlatform.componentWithName(componentName);
+ components.addToComponent(component);
+
+ // augmented 'component' shim
+ DefaultAugmentedOcPlatformComponent acomponent = new DefaultAugmentedOcPlatformComponent();
+
+ DefaultOpticalChannel channel = new DefaultOpticalChannel();
+
+ Config config = new DefaultConfig();
+ // TODO make these configurable
+ config.frequency(FrequencyType.of(BigInteger.valueOf(191500000)));
+ config.targetOutputPower(BigDecimal.valueOf(0.0));
+
+ channel.config(config);
+ acomponent.opticalChannel(channel);
+ component.addAugmentation(acomponent);
+
+ return ImmutableList.of(toDataNode(components));
+ }
+
+}
diff --git a/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/sub/PlainPlatform.java b/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/sub/PlainPlatform.java
new file mode 100644
index 0000000..74beaa6
--- /dev/null
+++ b/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/sub/PlainPlatform.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.odtn.cli.impl.sub;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.onosproject.yang.gen.v1.openconfigplatform.rev20161222.openconfigplatform.platformcomponenttop.components.Component;
+import org.onosproject.yang.gen.v1.openconfigplatform.rev20161222.openconfigplatform.platformcomponenttop.components.DefaultComponent;
+import org.onosproject.yang.gen.v1.openconfigplatform.rev20161222.openconfigplatform.platformcomponenttop.components.component.Config;
+import org.onosproject.yang.gen.v1.openconfigplatform.rev20161222.openconfigplatform.platformcomponenttop.components.component.DefaultConfig;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Utility methods dealing with OpenConfig component.
+ * <p>
+ * Split into classes for the purpose of avoiding "Config" class collisions.
+ */
+@Beta
+public abstract class PlainPlatform {
+
+ public static Component componentWithName(String componentName) {
+ checkNotNull(componentName, "componentName cannot be null");
+
+ Component component = new DefaultComponent();
+ component.name(componentName);
+ Config config = new DefaultConfig();
+ config.name(componentName);
+ component.config(config);
+ return component;
+ }
+}
diff --git a/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/sub/Transceiver.java b/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/sub/Transceiver.java
new file mode 100644
index 0000000..9d55408
--- /dev/null
+++ b/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/sub/Transceiver.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.odtn.cli.impl.sub;
+
+import static org.onosproject.odtn.utils.YangToolUtil.toDataNode;
+
+import java.util.List;
+
+import org.onosproject.yang.gen.v1.openconfigplatform.rev20161222.openconfigplatform.platformcomponenttop.DefaultComponents;
+import org.onosproject.yang.gen.v1.openconfigplatform.rev20161222.openconfigplatform.platformcomponenttop.components.Component;
+import org.onosproject.yang.gen.v1.openconfigplatformtransceiver.rev20170708.openconfigplatformtransceiver.components.component.DefaultAugmentedOcPlatformComponent;
+import org.onosproject.yang.gen.v1.openconfigplatformtransceiver.rev20170708.openconfigplatformtransceiver.porttransceivertop.DefaultTransceiver;
+import org.onosproject.yang.gen.v1.openconfigplatformtransceiver.rev20170708.openconfigplatformtransceiver.porttransceivertop.transceiver.Config;
+import org.onosproject.yang.gen.v1.openconfigplatformtransceiver.rev20170708.openconfigplatformtransceiver.porttransceivertop.transceiver.DefaultConfig;
+import org.onosproject.yang.gen.v1.openconfigtransporttypes.rev20170816.openconfigtransporttypes.Eth100GbaseLr4;
+import org.onosproject.yang.gen.v1.openconfigtransporttypes.rev20170816.openconfigtransporttypes.Qsfp28;
+import org.onosproject.yang.model.DataNode;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Utility methods dealing with OpenConfig transceiver.
+ * <p>
+ * Split into classes for the purpose of avoiding "Config" class collisions.
+ */
+@Beta
+public abstract class Transceiver {
+
+ public static List<DataNode> enable(String componentName, boolean enable) {
+
+ DefaultComponents components = new DefaultComponents();
+
+ Component component = PlainPlatform.componentWithName(componentName);
+ components.addToComponent(component);
+
+ // augmented 'component' shim
+ DefaultAugmentedOcPlatformComponent tcomponent = new DefaultAugmentedOcPlatformComponent();
+
+ DefaultTransceiver transceiver = new DefaultTransceiver();
+
+ Config configt = new DefaultConfig();
+ configt.enabled(enable); // phase 1.0 flag
+ transceiver.config(configt);
+ tcomponent.transceiver(transceiver);
+ component.addAugmentation(tcomponent);
+
+ return ImmutableList.of(toDataNode(components));
+ }
+
+ public static List<DataNode> preconf(String componentName) {
+ DefaultComponents components = new DefaultComponents();
+
+ Component component = PlainPlatform.componentWithName(componentName);
+ components.addToComponent(component);
+
+ // augmented 'component' shim
+ DefaultAugmentedOcPlatformComponent tcomponent = new DefaultAugmentedOcPlatformComponent();
+
+ DefaultTransceiver transceiver = new DefaultTransceiver();
+
+ Config configt = new DefaultConfig();
+ // TODO make these configurable
+ configt.formFactorPreconf(Qsfp28.class);
+ configt.ethernetPmdPreconf(Eth100GbaseLr4.class);
+ transceiver.config(configt);
+ tcomponent.transceiver(transceiver);
+ component.addAugmentation(tcomponent);
+
+ return ImmutableList.of(toDataNode(components));
+ }
+
+}
diff --git a/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/sub/package-info.java b/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/sub/package-info.java
new file mode 100644
index 0000000..ca8433c
--- /dev/null
+++ b/apps/odtn/src/main/java/org/onosproject/odtn/cli/impl/sub/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.
+ */
+/**
+ * sub-package for ODTN related CLI.
+ */
+package org.onosproject.odtn.cli.impl.sub;