blob: d4bfa8d2db6aa7c1009006573151f6468fdc7f90 [file] [log] [blame]
/*
* Copyright 2015-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.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.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 INSERT_VPLS_NAME =
COLOR_ERROR + "Missing the " + BOLD + "VPLS name." + RESET +
COLOR_ERROR + " Specifying a VPLS name is mandatory." +
RESET;
private static final String INSERT_ENCAP_TYPE =
COLOR_ERROR + "Missing the " + BOLD + "encapsulation type." +
RESET + COLOR_ERROR + " Encapsulation type is mandatory." +
RESET;
private static final String INSERT_INTERFACE =
COLOR_ERROR + "Missing the " + BOLD + "interface name." +
RESET + COLOR_ERROR + " Specifying an interface name is" +
" mandatory." + 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_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);
@Argument(index = 0, name = "command", description = "Command name (add-if|" +
"clean|create|delete|list|rem-if|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 or" +
" 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);
}
} else {
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) {
if (vplsName == null) {
print(INSERT_VPLS_NAME);
return;
}
if (ifaceName == null) {
print(INSERT_INTERFACE);
return;
}
if (!vplsExists(vplsName)) {
print(VPLS_NOT_FOUND, vplsName);
return;
}
if (!ifaceExists(ifaceName)) {
print(IFACE_NOT_FOUND, ifaceName);
return;
}
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 (vplsName == null || vplsName.isEmpty()) {
print(INSERT_VPLS_NAME);
return;
}
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 (vplsName == null) {
print(INSERT_VPLS_NAME);
return;
}
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);
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 (vplsName == null) {
print(INSERT_VPLS_NAME);
return;
}
if (ifaceName == null) {
print(INSERT_INTERFACE);
return;
}
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 (vplsName == null) {
print(INSERT_VPLS_NAME);
return;
}
if (encap == null) {
print(INSERT_ENCAP_TYPE);
return;
}
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();
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
print(SEPARATOR);
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;
}
}