blob: bf256688e78302cf5afe08427c65ab38485a2f8e [file] [log] [blame]
/*
* Copyright 2015-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.vpls.cli;
import com.google.common.collect.ImmutableSet;
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.api.VplsData;
import org.onosproject.vpls.api.Vpls;
import org.onosproject.vpls.api.VplsData.VplsState;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static com.google.common.base.Strings.isNullOrEmpty;
import static org.onosproject.vpls.api.VplsData.VplsState.*;
/**
* CLI to interact with the VPLS application.
*/
@Command(scope = "onos", name = "vpls",
description = "Manages the VPLS application")
public class VplsCommand extends AbstractShellCommand {
private static final Set<VplsState> CHANGING_STATE =
ImmutableSet.of(ADDING, REMOVING, UPDATING);
// 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\n" +
"State: %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 + ".";
protected static Vpls vpls;
protected static InterfaceService interfaceService;
@Argument(index = 0, name = "command", description = "Command name (add-if|" +
"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() {
if (vpls == null) {
vpls = get(Vpls.class);
}
if (interfaceService == null) {
interfaceService = get(InterfaceService.class);
}
VplsCommandEnum enumCommand = VplsCommandEnum.enumFromString(command);
if (enumCommand != null) {
switch (enumCommand) {
case ADD_IFACE:
addIface(vplsName, optArg);
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;
case CLEAN:
cleanVpls();
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
*/
protected void addIface(String vplsName, String ifaceName) {
if (vplsName == null) {
print(INSERT_VPLS_NAME);
return;
}
if (ifaceName == null) {
print(INSERT_INTERFACE);
return;
}
Interface iface = getInterface(ifaceName);
VplsData vplsData = vpls.getVpls(vplsName);
if (vplsData == null) {
print(VPLS_NOT_FOUND, vplsName);
return;
}
if (CHANGING_STATE.contains(vplsData.state())) {
// when a VPLS is updating, we shouldn't try modify it.
print("VPLS %s still updating, please wait it finished", vplsData.name());
return;
}
if (iface == null) {
print(IFACE_NOT_FOUND, ifaceName);
return;
}
if (isIfaceAssociated(iface)) {
print(IFACE_ALREADY_ASSOCIATED,
ifaceName, getVplsByInterface(iface).name());
return;
}
vpls.addInterface(vplsData, iface);
}
/**
* Creates a new VPLS.
*
* @param vplsName the name of the VLPS
*/
protected void create(String vplsName) {
if (vplsName == null || vplsName.isEmpty()) {
print(INSERT_VPLS_NAME);
return;
}
VplsData vplsData = vpls.getVpls(vplsName);
if (vplsData != null) {
print(VPLS_ALREADY_EXISTS, vplsName);
return;
}
vpls.createVpls(vplsName, EncapsulationType.NONE);
}
/**
* Deletes a VPLS.
*
* @param vplsName the name of the VLPS
*/
protected void delete(String vplsName) {
if (vplsName == null) {
print(INSERT_VPLS_NAME);
return;
}
VplsData vplsData = vpls.getVpls(vplsName);
if (vplsData == null) {
print(VPLS_NOT_FOUND, vplsName);
return;
}
if (CHANGING_STATE.contains(vplsData.state())) {
// when a VPLS is updating, we shouldn't try modify it.
print("VPLS %s still updating, please wait it finished", vplsData.name());
return;
}
vpls.removeVpls(vplsData);
}
/**
* Lists the configured VPLSs.
*/
protected void list() {
List<String> vplsNames = vpls.getAllVpls().stream()
.map(VplsData::name)
.collect(Collectors.toList());
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
*/
protected void removeIface(String vplsName, String ifaceName) {
if (vplsName == null) {
print(INSERT_VPLS_NAME);
return;
}
if (ifaceName == null) {
print(INSERT_INTERFACE);
return;
}
VplsData vplsData = vpls.getVpls(vplsName);
Interface iface = getInterface(ifaceName);
if (vplsData == null) {
print(VPLS_NOT_FOUND, vplsName);
return;
}
if (CHANGING_STATE.contains(vplsData.state())) {
// when a VPLS is updating, we shouldn't try modify it.
print("VPLS %s still updating, please wait it finished", vplsData.name());
return;
}
if (iface == null) {
print(IFACE_NOT_FOUND, ifaceName);
return;
}
if (!vplsData.interfaces().contains(iface)) {
print(IFACE_NOT_ASSOCIATED, ifaceName, vplsName);
return;
}
vpls.removeInterface(vplsData, iface);
}
/**
* Sets the encapsulation type for a VPLS.
*
* @param vplsName the name of the VPLS
* @param encap the encapsulation type
*/
protected void setEncap(String vplsName, String encap) {
if (vplsName == null) {
print(INSERT_VPLS_NAME);
return;
}
if (encap == null) {
print(INSERT_ENCAP_TYPE);
return;
}
VplsData vplsData = vpls.getVpls(vplsName);
if (vplsData == null) {
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;
}
vpls.setEncapsulationType(vplsData, encapType);
}
/**
* Shows the details of one or more VPLSs.
*
* @param vplsName the name of the VPLS
*/
protected void show(String vplsName) {
if (!isNullOrEmpty(vplsName)) {
// A VPLS name is provided. Check first if the VPLS exists
VplsData vplsData = vpls.getVpls(vplsName);
if (vplsData != null) {
Set<String> ifaceNames = vplsData.interfaces().stream()
.map(Interface::name)
.collect(Collectors.toSet());
print(VPLS_DISPLAY,
vplsName,
ifaceNames,
vplsData.encapsulationType().toString(),
vplsData.state());
} else {
print(VPLS_NOT_FOUND, vplsName);
}
} else {
Collection<VplsData> vplses = vpls.getAllVpls();
// No VPLS names are provided. Display all VPLSs configured
print(SEPARATOR);
vplses.forEach(vplsData -> {
Set<String> ifaceNames = vplsData.interfaces().stream()
.map(Interface::name)
.collect(Collectors.toSet());
print(VPLS_DISPLAY,
vplsData.name(),
ifaceNames,
vplsData.encapsulationType().toString(),
vplsData.state());
print(SEPARATOR);
});
}
}
/**
* Remove all VPLS.
*/
protected void cleanVpls() {
vpls.removeAllVpls();
}
/**
* States if an interface is already associated to a VPLS.
*
* @param iface the interface
* @return true if the interface is already associated to a VPLS; false
* otherwise
*/
private static boolean isIfaceAssociated(Interface iface) {
return vpls.getAllVpls()
.stream()
.map(VplsData::interfaces)
.flatMap(Collection::stream)
.anyMatch(iface::equals);
}
/**
* Gets a network interface by given interface name.
*
* @param interfaceName the interface name
* @return the network interface
*/
private Interface getInterface(String interfaceName) {
// FIXME: only returns first interface it found
// multiple interface with same name not support
return interfaceService.getInterfaces().stream()
.filter(iface -> iface.name().equals(interfaceName))
.findFirst()
.orElse(null);
}
/**
* Gets a VPLS related to the network interface.
*
* @param iface the network interface
* @return the VPLS related to the network interface
*/
private VplsData getVplsByInterface(Interface iface) {
return vpls.getAllVpls().stream()
.filter(vplsData -> vplsData.interfaces().contains(iface))
.findFirst()
.orElse(null);
}
}