ONOS-5419 Implementing new VPLS CLI
Change-Id: Id6a7ef785def15f5fcdc8d5ab8f9ab0f9a173065
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/cli/VplsCommand.java b/apps/vpls/src/main/java/org/onosproject/vpls/cli/VplsCommand.java
new file mode 100644
index 0000000..8263373
--- /dev/null
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/cli/VplsCommand.java
@@ -0,0 +1,374 @@
+/*
+ * 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
+ */
+package org.onosproject.vpls.cli;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.intf.Interface;
+import org.onosproject.incubator.net.intf.InterfaceService;
+import org.onosproject.net.EncapsulationType;
+import org.onosproject.vpls.config.VplsConfigService;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+
+/**
+ * CLI to interact with the VPLS application.
+ */
+@Command(scope = "onos", name = "vpls",
+ description = "Manages the VPLS application")
+public class VplsCommand extends AbstractShellCommand {
+
+ // Color codes and style
+ private static final String BOLD = "\u001B[1m";
+ private static final String COLOR_ERROR = "\u001B[31m";
+ private static final String RESET = "\u001B[0m";
+
+ // Messages and string formatter
+ private static final String ENCAP_NOT_FOUND =
+ COLOR_ERROR + "Encapsulation type " + BOLD + "%s" + RESET +
+ COLOR_ERROR + " not found" + RESET;
+
+ private static final String IFACE_NOT_FOUND =
+ COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR +
+ " not found" + RESET;
+
+ private static final String IFACE_ALREADY_ASSOCIATED =
+ COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR +
+ " already associated to VPLS " + BOLD + "%s" + RESET +
+ COLOR_ERROR + "" + RESET;
+
+ private static final String SEPARATOR = "----------------";
+
+ private static final String VPLS_ALREADY_EXISTS =
+ COLOR_ERROR + "VPLS " + BOLD + "%s" + RESET + COLOR_ERROR +
+ " already exists" + RESET;
+
+ private static final String VPLS_COMMAND_NOT_FOUND =
+ COLOR_ERROR + "VPLS command " + BOLD + "%s" + RESET + COLOR_ERROR +
+ " not found" + RESET;
+
+ private static final String VPLS_DISPLAY = "VPLS name: " + BOLD +
+ "%s" + RESET + "\nAssociated interfaces: %s\nEncapsulation: %s";
+
+ private static final String VPLS_LIST_TITLE =
+ BOLD + "Configured VPLSs" + RESET;
+
+ private static final String VPLS_NOT_FOUND =
+ COLOR_ERROR + "VPLS " + BOLD + "%s" + RESET + COLOR_ERROR +
+ " not found" + RESET;
+
+ private static final String IFACE_NOT_ASSOCIATED =
+ COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR +
+ " cannot be removed from VPLS " + BOLD + "%s" + RESET +
+ COLOR_ERROR + ". The interface is associated to another" +
+ "VPLS (" + BOLD + "%s" + RESET + COLOR_ERROR + ")" + RESET;
+
+ private static VplsConfigService vplsConfigService =
+ get(VplsConfigService.class);
+ private static InterfaceService interfaceService =
+ get(InterfaceService.class);
+
+ @Argument(index = 0, name = "command", description = "Command name (add|" +
+ "clean|create|delete|list|removeIface|set-encap|show)",
+ required = true, multiValued = false)
+ String command = null;
+
+ @Argument(index = 1, name = "vplsName", description = "The name of the VPLS",
+ required = false, multiValued = false)
+ String vplsName = null;
+
+ @Argument(index = 2, name = "optArg", description = "The interface name for" +
+ "all commands; the encapsulation type for set-encap",
+ required = false, multiValued = false)
+ String optArg = null;
+
+ @Override
+ protected void execute() {
+ VplsCommandEnum enumCommand = VplsCommandEnum.enumFromString(command);
+ if (enumCommand != null) {
+ switch (enumCommand) {
+ case ADD_IFACE:
+ addIface(vplsName, optArg);
+ break;
+ case CLEAN:
+ clean();
+ break;
+ case CREATE:
+ create(vplsName);
+ break;
+ case DELETE:
+ delete(vplsName);
+ break;
+ case LIST:
+ list();
+ break;
+ case REMOVE_IFACE:
+ removeIface(vplsName, optArg);
+ break;
+ case SET_ENCAP:
+ setEncap(vplsName, optArg);
+ break;
+ case SHOW:
+ show(vplsName);
+ break;
+ default:
+ print(VPLS_COMMAND_NOT_FOUND, command);
+ }
+ }
+ }
+
+ /**
+ * Adds an inteterface to a VPLS.
+ *
+ * @param vplsName the name of the VLPS
+ * @param ifaceName the name of the interface to add
+ */
+ private void addIface(String vplsName, String ifaceName) {
+ // Check if the VPLS exists
+ if (!vplsExists(vplsName)) {
+ print(VPLS_NOT_FOUND, vplsName);
+ return;
+ }
+ // Check if the interface exists
+ if (!ifaceExists(ifaceName)) {
+ print(IFACE_NOT_FOUND, ifaceName);
+ return;
+ }
+ // Check if the interface is already associated to a VPLS
+ if (isIfaceAssociated(ifaceName)) {
+ print(IFACE_ALREADY_ASSOCIATED,
+ ifaceName, vplsNameFromIfaceName(ifaceName));
+ return;
+ }
+
+ vplsConfigService.addIface(vplsName, ifaceName);
+ }
+
+ /**
+ * Cleans the VPLS configuration.
+ */
+ private void clean() {
+ vplsConfigService.cleanVplsConfig();
+ }
+
+ /**
+ * Creates a new VPLS.
+ *
+ * @param vplsName the name of the VLPS
+ */
+ private void create(String vplsName) {
+ if (vplsExists(vplsName)) {
+ print(VPLS_ALREADY_EXISTS, vplsName);
+ return;
+ }
+ vplsConfigService.addVpls(vplsName, Sets.newHashSet(), null);
+ }
+
+ /**
+ * Deletes a VPLS.
+ *
+ * @param vplsName the name of the VLPS
+ */
+ private void delete(String vplsName) {
+ if (!vplsExists(vplsName)) {
+ print(VPLS_NOT_FOUND, vplsName);
+ return;
+ }
+ vplsConfigService.removeVpls(vplsName);
+ }
+
+ /**
+ * Lists the configured VPLSs.
+ */
+ private void list() {
+ List<String> vplsNames = Lists.newArrayList(vplsConfigService.vplsNames());
+ Collections.sort(vplsNames);
+
+ print(VPLS_LIST_TITLE);
+ print(SEPARATOR);
+ vplsNames.forEach(vpls -> {
+ print(vpls);
+ });
+ }
+
+ /**
+ * Removes an interface from a VPLS.
+ *
+ * @param vplsName the name of the VLPS
+ * @param ifaceName the name of the interface to remove
+ */
+ private void removeIface(String vplsName, String ifaceName) {
+ if (!vplsExists(vplsName)) {
+ print(VPLS_NOT_FOUND, vplsName);
+ return;
+ }
+ if (!ifaceExists(ifaceName)) {
+ print(IFACE_NOT_FOUND, ifaceName);
+ return;
+ }
+ String vplsNameFromIfaceName = vplsNameFromIfaceName(ifaceName);
+ if (!vplsNameFromIfaceName.equals(vplsName)) {
+ print(IFACE_NOT_ASSOCIATED, ifaceName, vplsName, vplsNameFromIfaceName);
+ return;
+ }
+ vplsConfigService.removeIface(ifaceName);
+ }
+
+ /**
+ * Sets the encapsulation type for a VPLS.
+ *
+ * @param vplsName the name of the VPLS
+ * @param encap the encapsulation type
+ */
+ private void setEncap(String vplsName, String encap) {
+ if (!vplsExists(vplsName)) {
+ print(VPLS_NOT_FOUND, vplsName);
+ return;
+ }
+ EncapsulationType encapType = EncapsulationType.enumFromString(encap);
+ if (encapType.equals(EncapsulationType.NONE) &&
+ !encapType.toString().equals(encap)) {
+ print(ENCAP_NOT_FOUND, encap);
+ return;
+ }
+ vplsConfigService.setEncap(vplsName, encap);
+ }
+
+ /**
+ * Shows the details of one or more VPLSs.
+ *
+ * @param vplsName the name of the VPLS
+ */
+ private void show(String vplsName) {
+ List<String> vplsNames = Lists.newArrayList(vplsConfigService.vplsNames());
+ Collections.sort(vplsNames);
+
+ Map<String, EncapsulationType> encapByVplsName =
+ vplsConfigService.encapByVplsName();
+
+ print(VPLS_LIST_TITLE);
+ print(SEPARATOR);
+ if (!isNullOrEmpty(vplsName)) {
+ // A VPLS name is provided. Check first if the VPLS exists
+ if (vplsExists(vplsName)) {
+ print(VPLS_DISPLAY,
+ vplsName,
+ ifacesFromVplsName(vplsName).toString(),
+ encapByVplsName.get(vplsName).toString());
+ } else {
+ print(VPLS_NOT_FOUND, vplsName);
+ }
+ } else {
+ // No VPLS names are provided. Display all VPLSs configured
+ vplsNames.forEach(v -> {
+ print(VPLS_DISPLAY,
+ v,
+ ifacesFromVplsName(v).toString(),
+ encapByVplsName.get(v).toString());
+ print(SEPARATOR);
+ });
+ }
+ }
+
+ /**
+ * States if a VPLS exists or not.
+ *
+ * @param vplsName the name of the VPLS
+ * @return true if the VPLS exists; false otherwise
+ */
+ private static boolean vplsExists(String vplsName) {
+ return vplsConfigService.vplsNames().contains(vplsName);
+ }
+
+ /**
+ * States if an interface is defined or not in the system.
+ *
+ * @param ifaceName the name of the interface
+ * @return true if the interface is defined; false otherwise
+ */
+ private static boolean ifaceExists(String ifaceName) {
+ return vplsConfigService.allIfaces()
+ .stream()
+ .anyMatch(iface -> iface.name().equals(ifaceName));
+ }
+
+ /**
+ * States if an interface is already associated to a VPLS.
+ *
+ * @param ifaceName the name of the interface
+ * @return true if the interface is already associated to a VPLS; false
+ * otherwise
+ */
+ private static boolean isIfaceAssociated(String ifaceName) {
+ return vplsConfigService.ifaces()
+ .stream()
+ .anyMatch(iface -> iface.name().equals(ifaceName));
+ }
+
+ /**
+ * Returns the name of a VPLS, given the name of an interface associated to
+ * it.
+ *
+ * @param ifaceName the name of the interface
+ * @return the name of the VPLS that has the interface configured; null if
+ * the interface does not exist or is not associated to any VPLS
+ */
+ private static String vplsNameFromIfaceName(String ifaceName) {
+ String vplsName = null;
+
+ Optional<String> optVplsName = vplsConfigService.ifacesByVplsName()
+ .entries()
+ .stream()
+ .filter((entry -> entry.getValue().name().equals(ifaceName)))
+ .map(Map.Entry::getKey)
+ .findFirst();
+
+ if (optVplsName.isPresent()) {
+ vplsName = optVplsName.get();
+ }
+
+ return vplsName;
+ }
+
+ /**
+ * Returns a list of interfaces associated to a VPLS, given a VPLS name.
+ *
+ * @param vplsName the name of the VPLS
+ * @return the set of interfaces associated to the given VPLS; null if the
+ * VPLS is not found
+ */
+ private static Set<String> ifacesFromVplsName(String vplsName) {
+ if (!vplsExists(vplsName)) {
+ return null;
+ }
+ SetMultimap<String, Interface> ifacesByVplsName =
+ vplsConfigService.ifacesByVplsName();
+ Set<String> ifaceNames = Sets.newHashSet();
+
+ ifacesByVplsName.get(vplsName).forEach(iface -> ifaceNames.add(iface.name()));
+
+ return ifaceNames;
+ }
+}