CORD-535 Added purge and sync states CLIs
And improved result format of the existing CLIs
Change-Id: I49476ab52f77f6fadddf00dfc113c51153b300ed
diff --git a/src/main/java/org/opencord/cordvtn/api/net/VtnPort.java b/src/main/java/org/opencord/cordvtn/api/net/VtnPort.java
index 0ec1078..3ba4192 100644
--- a/src/main/java/org/opencord/cordvtn/api/net/VtnPort.java
+++ b/src/main/java/org/opencord/cordvtn/api/net/VtnPort.java
@@ -23,6 +23,7 @@
import org.onlab.packet.VlanId;
import org.openstack4j.model.network.Port;
+import java.util.Comparator;
import java.util.Objects;
import java.util.Set;
@@ -38,7 +39,7 @@
*/
public final class VtnPort extends ServicePort {
- private static final String ERR_IP_MISSING = "VTN port IP adderess is missing";
+ private static final String ERR_IP_MISSING = "VTN port IP address is missing";
private final NetworkId netId;
private final MacAddress mac;
@@ -56,6 +57,9 @@
this.ip = ip;
}
+ public static final Comparator<VtnPort> VTN_PORT_COMPARATOR =
+ (port1, port2) -> port1.netId().id().compareTo(port2.netId().id());
+
/**
* Returns the network ID of this port.
*
diff --git a/src/main/java/org/opencord/cordvtn/cli/CordVtnNetworkListCommand.java b/src/main/java/org/opencord/cordvtn/cli/CordVtnNetworkListCommand.java
new file mode 100644
index 0000000..a97a7ae
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/cli/CordVtnNetworkListCommand.java
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+package org.opencord.cordvtn.cli;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.opencord.cordvtn.api.core.CordVtnService;
+import org.opencord.cordvtn.api.net.VtnNetwork;
+
+import java.util.Set;
+
+import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
+
+/**
+ * Lists VTN networks.
+ */
+@Command(scope = "onos", name = "cordvtn-networks",
+ description = "Lists all VTN networks")
+public class CordVtnNetworkListCommand extends AbstractShellCommand {
+
+ private static final String FORMAT = "%-40s%-20s%-8s%-20s%s";
+
+ @Override
+ protected void execute() {
+ CordVtnService service = AbstractShellCommand.get(CordVtnService.class);
+ Set<VtnNetwork> networks = service.vtnNetworks();
+
+ if (outputJson()) {
+ try {
+ print("%s", mapper().writeValueAsString(json(networks)));
+ } catch (JsonProcessingException e) {
+ print("Failed to list networks in JSON format");
+ }
+ } else {
+ print(FORMAT, "ID", "Type", "VNI", "Subnet", "Service IP");
+ for (VtnNetwork net: networks) {
+ print(FORMAT, net.id(),
+ net.type(),
+ net.segmentId(),
+ net.subnet(),
+ net.serviceIp());
+ }
+ }
+ }
+
+ private JsonNode json(Set<VtnNetwork> networks) {
+ ArrayNode result = mapper().enable(INDENT_OUTPUT).createArrayNode();
+ for (VtnNetwork net: networks) {
+ ArrayNode providers = mapper().createArrayNode();
+ net.providers().forEach(provider -> providers.add(
+ mapper().createObjectNode()
+ .put("networkId", provider.id().id())
+ .put("type", provider.type().name())));
+
+ result.add(mapper().createObjectNode()
+ .put("id", net.id().id())
+ .put("type", net.type().name())
+ .put("vni", net.segmentId().id())
+ .put("subnet", net.subnet().toString())
+ .put("serviceIp", net.serviceIp().toString())
+ .set("providers", providers));
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/org/opencord/cordvtn/cli/CordVtnNodeCheckCommand.java b/src/main/java/org/opencord/cordvtn/cli/CordVtnNodeCheckCommand.java
index 17dbb45..9e988ca 100644
--- a/src/main/java/org/opencord/cordvtn/cli/CordVtnNodeCheckCommand.java
+++ b/src/main/java/org/opencord/cordvtn/cli/CordVtnNodeCheckCommand.java
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.opencord.cordvtn.cli;
import com.jcraft.jsch.Session;
@@ -45,6 +44,11 @@
required = true, multiValued = false)
private String hostname = null;
+ private static final String COMPLETE = "COMPLETE";
+ private static final String INCOMPLETE = "INCOMPLETE";
+ private static final String HINT = "hint: try init again if the state is INCOMPLETE" +
+ " but all settings OK";
+
@Override
protected void execute() {
CordVtnNodeManager nodeManager = AbstractShellCommand.get(CordVtnNodeManager.class);
@@ -60,7 +64,7 @@
print("Cannot find %s from registered nodes", hostname);
return;
}
-
+ print("Current state: %s (%s)", getState(nodeManager, node), HINT);
print("%n[Integration Bridge Status]");
Device device = deviceService.getDevice(node.integrationBridgeId());
if (device != null) {
@@ -131,4 +135,8 @@
isUp ? Boolean.TRUE : Boolean.FALSE,
isIp ? Boolean.TRUE : Boolean.FALSE);
}
+
+ private String getState(CordVtnNodeManager nodeManager, CordVtnNode node) {
+ return nodeManager.isNodeInitComplete(node) ? COMPLETE : INCOMPLETE;
+ }
}
diff --git a/src/main/java/org/opencord/cordvtn/cli/CordVtnNodeListCommand.java b/src/main/java/org/opencord/cordvtn/cli/CordVtnNodeListCommand.java
index 1a40397..5c995f1 100644
--- a/src/main/java/org/opencord/cordvtn/cli/CordVtnNodeListCommand.java
+++ b/src/main/java/org/opencord/cordvtn/cli/CordVtnNodeListCommand.java
@@ -13,11 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.opencord.cordvtn.cli;
+import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
@@ -27,6 +26,8 @@
import java.util.Collections;
import java.util.List;
+import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
+
/**
* Lists all nodes registered to the service.
*/
@@ -36,6 +37,7 @@
private static final String COMPLETE = "COMPLETE";
private static final String INCOMPLETE = "INCOMPLETE";
+ private static final String FORMAT = "%-30s%-20s%-20s%-15s%-24s%s";
@Override
protected void execute() {
@@ -44,15 +46,21 @@
Collections.sort(nodes, CordVtnNode.CORDVTN_NODE_COMPARATOR);
if (outputJson()) {
- print("%s", json(nodeManager, nodes));
+ try {
+ print("%s", mapper().writeValueAsString(json(nodeManager, nodes)));
+ } catch (JsonProcessingException e) {
+ print("Failed to list networks in JSON format");
+ }
} else {
+ print(FORMAT, "Hostname", "Management IP", "Data IP", "Data Iface",
+ "Br-int", "State");
+
for (CordVtnNode node : nodes) {
- print("hostname=%s, hostMgmtIp=%s, dataIp=%s, br-int=%s, dataIface=%s, init=%s",
- node.hostname(),
+ print(FORMAT, node.hostname(),
node.hostMgmtIp().cidr(),
node.dataIp().cidr(),
- node.integrationBridgeId().toString(),
node.dataIface(),
+ node.integrationBridgeId().toString(),
getState(nodeManager, node));
}
print("Total %s nodes", nodeManager.getNodeCount());
@@ -60,16 +68,15 @@
}
private JsonNode json(CordVtnNodeManager nodeManager, List<CordVtnNode> nodes) {
- ObjectMapper mapper = new ObjectMapper();
- ArrayNode result = mapper.createArrayNode();
+ ArrayNode result = mapper().enable(INDENT_OUTPUT).createArrayNode();
for (CordVtnNode node : nodes) {
- result.add(mapper.createObjectNode()
+ result.add(mapper().createObjectNode()
.put("hostname", node.hostname())
- .put("hostManagementIp", node.hostMgmtIp().cidr())
- .put("dataPlaneIp", node.dataIp().cidr())
+ .put("managementIp", node.hostMgmtIp().cidr())
+ .put("dataIp", node.dataIp().cidr())
+ .put("dataInterface", node.dataIface())
.put("bridgeId", node.integrationBridgeId().toString())
- .put("dataPlaneInterface", node.dataIface())
- .put("init", getState(nodeManager, node)));
+ .put("state", getState(nodeManager, node)));
}
return result;
}
diff --git a/src/main/java/org/opencord/cordvtn/cli/CordVtnPortListCommand.java b/src/main/java/org/opencord/cordvtn/cli/CordVtnPortListCommand.java
new file mode 100644
index 0000000..361b220
--- /dev/null
+++ b/src/main/java/org/opencord/cordvtn/cli/CordVtnPortListCommand.java
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+package org.opencord.cordvtn.cli;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.opencord.cordvtn.api.core.CordVtnService;
+import org.opencord.cordvtn.api.net.NetworkId;
+import org.opencord.cordvtn.api.net.VtnNetwork;
+import org.opencord.cordvtn.api.net.VtnPort;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
+
+/**
+ * Lists VTN networks.
+ */
+@Command(scope = "onos", name = "cordvtn-ports",
+ description = "Lists all VTN ports")
+public class CordVtnPortListCommand extends AbstractShellCommand {
+
+ private static final String FORMAT = "%-40s%-20s%-18s%-6s%s";
+
+ @Argument(name = "networkId", description = "Network ID")
+ private String networkId = null;
+
+ @Override
+ protected void execute() {
+ CordVtnService service = AbstractShellCommand.get(CordVtnService.class);
+
+ List<VtnPort> ports;
+ if (Strings.isNullOrEmpty(networkId)) {
+ ports = Lists.newArrayList(service.vtnPorts());
+ } else {
+ VtnNetwork vtnNet = service.vtnNetwork(NetworkId.of(networkId));
+ if (vtnNet == null) {
+ print("Network %s does not exists", networkId);
+ return;
+ }
+ ports = service.vtnPorts().stream()
+ .filter(p -> p.netId().equals(NetworkId.of(networkId)))
+ .collect(Collectors.toList());
+ Collections.sort(ports, VtnPort.VTN_PORT_COMPARATOR);
+ }
+
+ if (outputJson()) {
+ try {
+ print("%s", mapper().writeValueAsString(json(ports)));
+ } catch (JsonProcessingException e) {
+ print("Failed to list networks in JSON format");
+ }
+ } else {
+ print(FORMAT, "ID", "MAC", "IP", "VLAN", "Additional IPs");
+ for (VtnPort port: ports) {
+ List<String> floatingIps = port.addressPairs().stream()
+ .map(ip -> ip.ip().toString())
+ .collect(Collectors.toList());
+ print(FORMAT, port.id(),
+ port.mac(),
+ port.ip(),
+ port.vlanId().isPresent() ? port.vlanId().get() : "",
+ floatingIps.isEmpty() ? "" : floatingIps);
+ }
+ }
+ }
+
+ private JsonNode json(List<VtnPort> ports) {
+ ArrayNode result = mapper().enable(INDENT_OUTPUT).createArrayNode();
+ for (VtnPort port: ports) {
+ ArrayNode addrPairs = mapper().createArrayNode();
+ port.addressPairs().forEach(pair -> addrPairs.add(
+ mapper().createObjectNode()
+ .put("ip", pair.ip().toString())
+ .put("mac", pair.mac().toString())));
+
+ result.add(mapper().createObjectNode()
+ .put("id", port.id().id())
+ .put("networkId", port.netId().id())
+ .put("mac", port.mac().toString())
+ .put("ip", port.ip().toString())
+ .put("vlan", port.vlanId().isPresent() ?
+ port.vlanId().get().toString() : null)
+ .set("addressPairs", addrPairs));
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/org/opencord/cordvtn/cli/CordVtnFlushRules.java b/src/main/java/org/opencord/cordvtn/cli/CordVtnPurgeRulesCommand.java
similarity index 79%
rename from src/main/java/org/opencord/cordvtn/cli/CordVtnFlushRules.java
rename to src/main/java/org/opencord/cordvtn/cli/CordVtnPurgeRulesCommand.java
index 3669b48..06f5aee 100644
--- a/src/main/java/org/opencord/cordvtn/cli/CordVtnFlushRules.java
+++ b/src/main/java/org/opencord/cordvtn/cli/CordVtnPurgeRulesCommand.java
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.opencord.cordvtn.cli;
import org.apache.karaf.shell.commands.Command;
@@ -21,16 +20,15 @@
import org.opencord.cordvtn.impl.CordVtnPipeline;
/**
- * Deletes nodes from the service.
+ * Purges all flow rules installed by CORD VTN service.
*/
-@Command(scope = "onos", name = "cordvtn-flush-rules",
- description = "Flush flow rules installed by CORD VTN")
-public class CordVtnFlushRules extends AbstractShellCommand {
+@Command(scope = "onos", name = "cordvtn-purge-rules",
+ description = "Purges all flow rules installed by CORD VTN")
+public class CordVtnPurgeRulesCommand extends AbstractShellCommand {
@Override
protected void execute() {
CordVtnPipeline pipeline = AbstractShellCommand.get(CordVtnPipeline.class);
pipeline.flushRules();
- print("Successfully flushed");
}
}
diff --git a/src/main/java/org/opencord/cordvtn/cli/CordVtnFlushRules.java b/src/main/java/org/opencord/cordvtn/cli/CordVtnPurgeStatesCommand.java
similarity index 65%
copy from src/main/java/org/opencord/cordvtn/cli/CordVtnFlushRules.java
copy to src/main/java/org/opencord/cordvtn/cli/CordVtnPurgeStatesCommand.java
index 3669b48..b26ec66 100644
--- a/src/main/java/org/opencord/cordvtn/cli/CordVtnFlushRules.java
+++ b/src/main/java/org/opencord/cordvtn/cli/CordVtnPurgeStatesCommand.java
@@ -13,24 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.opencord.cordvtn.cli;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
-import org.opencord.cordvtn.impl.CordVtnPipeline;
+import org.opencord.cordvtn.api.core.CordVtnAdminService;
/**
- * Deletes nodes from the service.
+ * Purges internal network states.
*/
-@Command(scope = "onos", name = "cordvtn-flush-rules",
- description = "Flush flow rules installed by CORD VTN")
-public class CordVtnFlushRules extends AbstractShellCommand {
+@Command(scope = "onos", name = "cordvtn-purge-states",
+ description = "Purges network states")
+public class CordVtnPurgeStatesCommand extends AbstractShellCommand {
@Override
protected void execute() {
- CordVtnPipeline pipeline = AbstractShellCommand.get(CordVtnPipeline.class);
- pipeline.flushRules();
- print("Successfully flushed");
+ CordVtnAdminService adminService =
+ AbstractShellCommand.get(CordVtnAdminService.class);
+ adminService.purgeStates();
}
}
diff --git a/src/main/java/org/opencord/cordvtn/cli/CordVtnFlushRules.java b/src/main/java/org/opencord/cordvtn/cli/CordVtnSyncStatesCommand.java
similarity index 63%
copy from src/main/java/org/opencord/cordvtn/cli/CordVtnFlushRules.java
copy to src/main/java/org/opencord/cordvtn/cli/CordVtnSyncStatesCommand.java
index 3669b48..5540391 100644
--- a/src/main/java/org/opencord/cordvtn/cli/CordVtnFlushRules.java
+++ b/src/main/java/org/opencord/cordvtn/cli/CordVtnSyncStatesCommand.java
@@ -13,24 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.opencord.cordvtn.cli;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
-import org.opencord.cordvtn.impl.CordVtnPipeline;
+import org.opencord.cordvtn.api.core.CordVtnAdminService;
/**
- * Deletes nodes from the service.
+ * Synchronizes network states with external services.
*/
-@Command(scope = "onos", name = "cordvtn-flush-rules",
- description = "Flush flow rules installed by CORD VTN")
-public class CordVtnFlushRules extends AbstractShellCommand {
+@Command(scope = "onos", name = "cordvtn-sync-states",
+ description = "Synchronizes network states with external services")
+public class CordVtnSyncStatesCommand extends AbstractShellCommand {
@Override
protected void execute() {
- CordVtnPipeline pipeline = AbstractShellCommand.get(CordVtnPipeline.class);
- pipeline.flushRules();
- print("Successfully flushed");
+ CordVtnAdminService adminService =
+ AbstractShellCommand.get(CordVtnAdminService.class);
+ adminService.syncStates();
}
}
diff --git a/src/main/java/org/opencord/cordvtn/impl/CordVtnNodeManager.java b/src/main/java/org/opencord/cordvtn/impl/CordVtnNodeManager.java
index b1858a3..78cc228 100644
--- a/src/main/java/org/opencord/cordvtn/impl/CordVtnNodeManager.java
+++ b/src/main/java/org/opencord/cordvtn/impl/CordVtnNodeManager.java
@@ -289,7 +289,7 @@
*/
public boolean isNodeInitComplete(CordVtnNode node) {
checkNotNull(node);
- return getNodeState(node).equals(NodeState.COMPLETE);
+ return isNodeStateComplete(node);
}
/**
diff --git a/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 0e717d5..bdb9335 100644
--- a/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -29,7 +29,19 @@
<action class="org.opencord.cordvtn.cli.CordVtnNodeCheckCommand"/>
</command>
<command>
- <action class="org.opencord.cordvtn.cli.CordVtnFlushRules"/>
+ <action class="org.opencord.cordvtn.cli.CordVtnPurgeRulesCommand"/>
+ </command>
+ <command>
+ <action class="org.opencord.cordvtn.cli.CordVtnPurgeStatesCommand"/>
+ </command>
+ <command>
+ <action class="org.opencord.cordvtn.cli.CordVtnSyncStatesCommand"/>
+ </command>
+ <command>
+ <action class="org.opencord.cordvtn.cli.CordVtnNetworkListCommand"/>
+ </command>
+ <command>
+ <action class="org.opencord.cordvtn.cli.CordVtnPortListCommand"/>
</command>
</command-bundle>
</blueprint>