blob: 47184533ba6247b213199ec37a17d2fde1a030f5 [file] [log] [blame]
Luca Pretedce16f82016-11-22 13:11:56 -08001/*
Luca Prete99f6f282016-12-05 15:33:36 -08002 * Copyright 2015-present Open Networking Laboratory
Luca Pretedce16f82016-11-22 13:11:56 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
Luca Prete99f6f282016-12-05 15:33:36 -080014 * limitations under the License.
Luca Pretedce16f82016-11-22 13:11:56 -080015 */
16package org.onosproject.vpls.cli;
17
Luca Pretedce16f82016-11-22 13:11:56 -080018import org.apache.karaf.shell.commands.Argument;
19import org.apache.karaf.shell.commands.Command;
20import org.onosproject.cli.AbstractShellCommand;
21import org.onosproject.incubator.net.intf.Interface;
Yi Tsengf4e13e32017-03-30 15:38:39 -070022import org.onosproject.incubator.net.intf.InterfaceService;
Luca Pretedce16f82016-11-22 13:11:56 -080023import org.onosproject.net.EncapsulationType;
Yi Tsengf4e13e32017-03-30 15:38:39 -070024import org.onosproject.vpls.api.VplsData;
25import org.onosproject.vpls.api.Vpls;
Luca Pretedce16f82016-11-22 13:11:56 -080026
Yi Tsengf4e13e32017-03-30 15:38:39 -070027import java.util.Collection;
Luca Pretedce16f82016-11-22 13:11:56 -080028import java.util.Collections;
29import java.util.List;
Luca Pretedce16f82016-11-22 13:11:56 -080030import java.util.Set;
Yi Tsengf4e13e32017-03-30 15:38:39 -070031import java.util.stream.Collectors;
Luca Pretedce16f82016-11-22 13:11:56 -080032
33import static com.google.common.base.Strings.isNullOrEmpty;
34
Yi Tsengf4e13e32017-03-30 15:38:39 -070035
Luca Pretedce16f82016-11-22 13:11:56 -080036/**
37 * CLI to interact with the VPLS application.
38 */
39@Command(scope = "onos", name = "vpls",
40 description = "Manages the VPLS application")
41public class VplsCommand extends AbstractShellCommand {
42
43 // Color codes and style
44 private static final String BOLD = "\u001B[1m";
45 private static final String COLOR_ERROR = "\u001B[31m";
46 private static final String RESET = "\u001B[0m";
47
48 // Messages and string formatter
49 private static final String ENCAP_NOT_FOUND =
50 COLOR_ERROR + "Encapsulation type " + BOLD + "%s" + RESET +
51 COLOR_ERROR + " not found" + RESET;
52
53 private static final String IFACE_NOT_FOUND =
54 COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR +
55 " not found" + RESET;
56
57 private static final String IFACE_ALREADY_ASSOCIATED =
58 COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR +
59 " already associated to VPLS " + BOLD + "%s" + RESET +
60 COLOR_ERROR + "" + RESET;
61
Luca Prete8dbbea82016-12-07 18:10:10 -080062 private static final String INSERT_VPLS_NAME =
63 COLOR_ERROR + "Missing the " + BOLD + "VPLS name." + RESET +
64 COLOR_ERROR + " Specifying a VPLS name is mandatory." +
65 RESET;
66
67 private static final String INSERT_ENCAP_TYPE =
68 COLOR_ERROR + "Missing the " + BOLD + "encapsulation type." +
69 RESET + COLOR_ERROR + " Encapsulation type is mandatory." +
70 RESET;
71
72 private static final String INSERT_INTERFACE =
73 COLOR_ERROR + "Missing the " + BOLD + "interface name." +
74 RESET + COLOR_ERROR + " Specifying an interface name is" +
75 " mandatory." + RESET;
76
Luca Pretedce16f82016-11-22 13:11:56 -080077 private static final String SEPARATOR = "----------------";
78
79 private static final String VPLS_ALREADY_EXISTS =
80 COLOR_ERROR + "VPLS " + BOLD + "%s" + RESET + COLOR_ERROR +
81 " already exists" + RESET;
82
83 private static final String VPLS_COMMAND_NOT_FOUND =
84 COLOR_ERROR + "VPLS command " + BOLD + "%s" + RESET + COLOR_ERROR +
85 " not found" + RESET;
86
87 private static final String VPLS_DISPLAY = "VPLS name: " + BOLD +
Yi Tsengf4e13e32017-03-30 15:38:39 -070088 "%s" + RESET + "\nAssociated interfaces: %s\nEncapsulation: %s\n" +
89 "State: %s";
Luca Pretedce16f82016-11-22 13:11:56 -080090
Luca Pretedce16f82016-11-22 13:11:56 -080091 private static final String VPLS_NOT_FOUND =
92 COLOR_ERROR + "VPLS " + BOLD + "%s" + RESET + COLOR_ERROR +
93 " not found" + RESET;
94
95 private static final String IFACE_NOT_ASSOCIATED =
96 COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR +
Yi Tsengf4e13e32017-03-30 15:38:39 -070097 " cannot be removed from VPLS " + BOLD + "%s" + RESET + ".";
Luca Pretedce16f82016-11-22 13:11:56 -080098
Yi Tsengf4e13e32017-03-30 15:38:39 -070099 protected static Vpls vpls;
100 protected static InterfaceService interfaceService;
Luca Pretedce16f82016-11-22 13:11:56 -0800101
Luca Prete8dbbea82016-12-07 18:10:10 -0800102 @Argument(index = 0, name = "command", description = "Command name (add-if|" +
Yi Tsengf4e13e32017-03-30 15:38:39 -0700103 "create|delete|list|rem-if|set-encap|show)",
Luca Pretedce16f82016-11-22 13:11:56 -0800104 required = true, multiValued = false)
105 String command = null;
106
107 @Argument(index = 1, name = "vplsName", description = "The name of the VPLS",
108 required = false, multiValued = false)
109 String vplsName = null;
110
Luca Prete8dbbea82016-12-07 18:10:10 -0800111 @Argument(index = 2, name = "optArg", description = "The interface name or" +
112 " the encapsulation type for set-encap",
Luca Pretedce16f82016-11-22 13:11:56 -0800113 required = false, multiValued = false)
114 String optArg = null;
115
116 @Override
117 protected void execute() {
Yi Tsengf4e13e32017-03-30 15:38:39 -0700118 if (vpls == null) {
119 vpls = get(Vpls.class);
120 }
121 if (interfaceService == null) {
122 interfaceService = get(InterfaceService.class);
123 }
124
Luca Pretedce16f82016-11-22 13:11:56 -0800125 VplsCommandEnum enumCommand = VplsCommandEnum.enumFromString(command);
126 if (enumCommand != null) {
127 switch (enumCommand) {
128 case ADD_IFACE:
129 addIface(vplsName, optArg);
130 break;
Luca Pretedce16f82016-11-22 13:11:56 -0800131 case CREATE:
132 create(vplsName);
133 break;
134 case DELETE:
135 delete(vplsName);
136 break;
137 case LIST:
138 list();
139 break;
140 case REMOVE_IFACE:
141 removeIface(vplsName, optArg);
142 break;
143 case SET_ENCAP:
144 setEncap(vplsName, optArg);
145 break;
146 case SHOW:
147 show(vplsName);
148 break;
Yi Tsengf4e13e32017-03-30 15:38:39 -0700149 case CLEAN:
150 cleanVpls();
151 break;
Luca Pretedce16f82016-11-22 13:11:56 -0800152 default:
153 print(VPLS_COMMAND_NOT_FOUND, command);
154 }
Luca Prete8dbbea82016-12-07 18:10:10 -0800155 } else {
156 print(VPLS_COMMAND_NOT_FOUND, command);
Luca Pretedce16f82016-11-22 13:11:56 -0800157 }
158 }
159
160 /**
161 * Adds an inteterface to a VPLS.
162 *
163 * @param vplsName the name of the VLPS
164 * @param ifaceName the name of the interface to add
165 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700166 protected void addIface(String vplsName, String ifaceName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800167 if (vplsName == null) {
168 print(INSERT_VPLS_NAME);
169 return;
170 }
171 if (ifaceName == null) {
172 print(INSERT_INTERFACE);
173 return;
174 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700175
176 Interface iface = getInterface(ifaceName);
177 VplsData vplsData = vpls.getVpls(vplsName);
178
179 if (vplsData == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800180 print(VPLS_NOT_FOUND, vplsName);
181 return;
182 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700183 if (iface == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800184 print(IFACE_NOT_FOUND, ifaceName);
185 return;
186 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700187 if (isIfaceAssociated(iface)) {
Luca Pretedce16f82016-11-22 13:11:56 -0800188 print(IFACE_ALREADY_ASSOCIATED,
Yi Tsengf4e13e32017-03-30 15:38:39 -0700189 ifaceName, getVplsByInterface(iface).name());
Luca Pretedce16f82016-11-22 13:11:56 -0800190 return;
191 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700192 vpls.addInterface(vplsData, iface);
Luca Pretedce16f82016-11-22 13:11:56 -0800193 }
194
195 /**
196 * Creates a new VPLS.
197 *
198 * @param vplsName the name of the VLPS
199 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700200 protected void create(String vplsName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800201 if (vplsName == null || vplsName.isEmpty()) {
202 print(INSERT_VPLS_NAME);
203 return;
204 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700205 VplsData vplsData = vpls.getVpls(vplsName);
206 if (vplsData != null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800207 print(VPLS_ALREADY_EXISTS, vplsName);
208 return;
209 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700210 vpls.createVpls(vplsName, EncapsulationType.NONE);
Luca Pretedce16f82016-11-22 13:11:56 -0800211 }
212
213 /**
214 * Deletes a VPLS.
215 *
216 * @param vplsName the name of the VLPS
217 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700218 protected void delete(String vplsName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800219 if (vplsName == null) {
220 print(INSERT_VPLS_NAME);
221 return;
222 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700223 VplsData vplsData = vpls.getVpls(vplsName);
224 if (vplsData == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800225 print(VPLS_NOT_FOUND, vplsName);
226 return;
227 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700228 vpls.removeVpls(vplsData);
Luca Pretedce16f82016-11-22 13:11:56 -0800229 }
230
231 /**
232 * Lists the configured VPLSs.
233 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700234 protected void list() {
235 List<String> vplsNames = vpls.getAllVpls().stream()
236 .map(VplsData::name)
237 .collect(Collectors.toList());
Luca Pretedce16f82016-11-22 13:11:56 -0800238 Collections.sort(vplsNames);
239
Luca Pretedce16f82016-11-22 13:11:56 -0800240 vplsNames.forEach(vpls -> {
241 print(vpls);
242 });
243 }
244
245 /**
246 * Removes an interface from a VPLS.
247 *
248 * @param vplsName the name of the VLPS
249 * @param ifaceName the name of the interface to remove
250 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700251 protected void removeIface(String vplsName, String ifaceName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800252 if (vplsName == null) {
253 print(INSERT_VPLS_NAME);
254 return;
255 }
256 if (ifaceName == null) {
257 print(INSERT_INTERFACE);
258 return;
259 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700260 VplsData vplsData = vpls.getVpls(vplsName);
261 Interface iface = getInterface(ifaceName);
262 if (vplsData == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800263 print(VPLS_NOT_FOUND, vplsName);
264 return;
265 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700266 if (iface == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800267 print(IFACE_NOT_FOUND, ifaceName);
268 return;
269 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700270 if (!vplsData.interfaces().contains(iface)) {
271 print(IFACE_NOT_ASSOCIATED, ifaceName, vplsName);
Luca Pretedce16f82016-11-22 13:11:56 -0800272 return;
273 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700274 vpls.removeInterface(vplsData, iface);
Luca Pretedce16f82016-11-22 13:11:56 -0800275 }
276
277 /**
278 * Sets the encapsulation type for a VPLS.
279 *
280 * @param vplsName the name of the VPLS
281 * @param encap the encapsulation type
282 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700283 protected void setEncap(String vplsName, String encap) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800284 if (vplsName == null) {
285 print(INSERT_VPLS_NAME);
286 return;
287 }
288 if (encap == null) {
289 print(INSERT_ENCAP_TYPE);
290 return;
291 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700292 VplsData vplsData = vpls.getVpls(vplsName);
293 if (vplsData == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800294 print(VPLS_NOT_FOUND, vplsName);
295 return;
296 }
297 EncapsulationType encapType = EncapsulationType.enumFromString(encap);
298 if (encapType.equals(EncapsulationType.NONE) &&
299 !encapType.toString().equals(encap)) {
300 print(ENCAP_NOT_FOUND, encap);
301 return;
302 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700303 vpls.setEncapsulationType(vplsData, encapType);
Luca Pretedce16f82016-11-22 13:11:56 -0800304 }
305
306 /**
307 * Shows the details of one or more VPLSs.
308 *
309 * @param vplsName the name of the VPLS
310 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700311 protected void show(String vplsName) {
Luca Pretedce16f82016-11-22 13:11:56 -0800312 if (!isNullOrEmpty(vplsName)) {
313 // A VPLS name is provided. Check first if the VPLS exists
Yi Tsengf4e13e32017-03-30 15:38:39 -0700314 VplsData vplsData = vpls.getVpls(vplsName);
315 if (vplsData != null) {
316 Set<String> ifaceNames = vplsData.interfaces().stream()
317 .map(Interface::name)
318 .collect(Collectors.toSet());
Luca Pretedce16f82016-11-22 13:11:56 -0800319 print(VPLS_DISPLAY,
320 vplsName,
Yi Tsengf4e13e32017-03-30 15:38:39 -0700321 ifaceNames,
322 vplsData.encapsulationType().toString(),
323 vplsData.state());
Luca Pretedce16f82016-11-22 13:11:56 -0800324 } else {
325 print(VPLS_NOT_FOUND, vplsName);
326 }
327 } else {
Yi Tsengf4e13e32017-03-30 15:38:39 -0700328 Collection<VplsData> vplses = vpls.getAllVpls();
Luca Pretedce16f82016-11-22 13:11:56 -0800329 // No VPLS names are provided. Display all VPLSs configured
Luca Prete8dbbea82016-12-07 18:10:10 -0800330 print(SEPARATOR);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700331 vplses.forEach(vplsData -> {
332 Set<String> ifaceNames = vplsData.interfaces().stream()
333 .map(Interface::name)
334 .collect(Collectors.toSet());
Luca Pretedce16f82016-11-22 13:11:56 -0800335 print(VPLS_DISPLAY,
Yi Tsengf4e13e32017-03-30 15:38:39 -0700336 vplsData.name(),
337 ifaceNames,
338 vplsData.encapsulationType().toString(),
339 vplsData.state());
Luca Pretedce16f82016-11-22 13:11:56 -0800340 print(SEPARATOR);
341 });
342 }
343 }
344
345 /**
Yi Tsengf4e13e32017-03-30 15:38:39 -0700346 * Remove all VPLS.
Luca Pretedce16f82016-11-22 13:11:56 -0800347 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700348 protected void cleanVpls() {
349 vpls.removeAllVpls();
Luca Pretedce16f82016-11-22 13:11:56 -0800350 }
351
Luca Pretedce16f82016-11-22 13:11:56 -0800352
353 /**
354 * States if an interface is already associated to a VPLS.
355 *
Yi Tsengf4e13e32017-03-30 15:38:39 -0700356 * @param iface the interface
Luca Pretedce16f82016-11-22 13:11:56 -0800357 * @return true if the interface is already associated to a VPLS; false
358 * otherwise
359 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700360 private static boolean isIfaceAssociated(Interface iface) {
361 return vpls.getAllVpls()
Luca Pretedce16f82016-11-22 13:11:56 -0800362 .stream()
Yi Tsengf4e13e32017-03-30 15:38:39 -0700363 .map(VplsData::interfaces)
364 .flatMap(Collection::stream)
365 .anyMatch(iface::equals);
Luca Pretedce16f82016-11-22 13:11:56 -0800366 }
367
368 /**
Yi Tsengf4e13e32017-03-30 15:38:39 -0700369 * Gets a network interface by given interface name.
Luca Pretedce16f82016-11-22 13:11:56 -0800370 *
Yi Tsengf4e13e32017-03-30 15:38:39 -0700371 * @param interfaceName the interface name
372 * @return the network interface
Luca Pretedce16f82016-11-22 13:11:56 -0800373 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700374 private Interface getInterface(String interfaceName) {
375 // FIXME: only returns first interface it found
376 // multiple interface with same name not support
377 return interfaceService.getInterfaces().stream()
378 .filter(iface -> iface.name().equals(interfaceName))
379 .findFirst()
380 .orElse(null);
Luca Pretedce16f82016-11-22 13:11:56 -0800381 }
382
383 /**
Yi Tsengf4e13e32017-03-30 15:38:39 -0700384 * Gets a VPLS related to the network interface.
Luca Pretedce16f82016-11-22 13:11:56 -0800385 *
Yi Tsengf4e13e32017-03-30 15:38:39 -0700386 * @param iface the network interface
387 * @return the VPLS related to the network interface
Luca Pretedce16f82016-11-22 13:11:56 -0800388 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700389 private VplsData getVplsByInterface(Interface iface) {
390 return vpls.getAllVpls().stream()
391 .filter(vplsData -> vplsData.interfaces().contains(iface))
392 .findFirst()
393 .orElse(null);
Luca Pretedce16f82016-11-22 13:11:56 -0800394 }
395}