blob: 1f644225a4ca605c31e6086156b771bdf4d0c389 [file] [log] [blame]
Luca Pretedce16f82016-11-22 13:11:56 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
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
Yi Tseng3069c612017-05-26 17:09:43 -070018import com.google.common.collect.ImmutableSet;
Ray Milkey86ad7bb2018-09-27 12:32:28 -070019import org.apache.karaf.shell.api.action.Argument;
20import org.apache.karaf.shell.api.action.Command;
Ray Milkey7a2dee52018-09-28 10:58:28 -070021import org.apache.karaf.shell.api.action.lifecycle.Service;
Luca Pretedce16f82016-11-22 13:11:56 -080022import org.onosproject.cli.AbstractShellCommand;
Ray Milkeyfacf2862017-08-03 11:58:29 -070023import org.onosproject.net.intf.Interface;
24import org.onosproject.net.intf.InterfaceService;
Luca Pretedce16f82016-11-22 13:11:56 -080025import org.onosproject.net.EncapsulationType;
Yi Tsengf4e13e32017-03-30 15:38:39 -070026import org.onosproject.vpls.api.VplsData;
27import org.onosproject.vpls.api.Vpls;
Yi Tseng3069c612017-05-26 17:09:43 -070028import org.onosproject.vpls.api.VplsData.VplsState;
Luca Pretedce16f82016-11-22 13:11:56 -080029
Yi Tsengf4e13e32017-03-30 15:38:39 -070030import java.util.Collection;
Luca Pretedce16f82016-11-22 13:11:56 -080031import java.util.Collections;
32import java.util.List;
Luca Pretedce16f82016-11-22 13:11:56 -080033import java.util.Set;
Yi Tsengf4e13e32017-03-30 15:38:39 -070034import java.util.stream.Collectors;
Luca Pretedce16f82016-11-22 13:11:56 -080035
36import static com.google.common.base.Strings.isNullOrEmpty;
Yi Tseng3069c612017-05-26 17:09:43 -070037import static org.onosproject.vpls.api.VplsData.VplsState.*;
Luca Pretedce16f82016-11-22 13:11:56 -080038
Yi Tsengf4e13e32017-03-30 15:38:39 -070039
Luca Pretedce16f82016-11-22 13:11:56 -080040/**
41 * CLI to interact with the VPLS application.
42 */
Ray Milkey7a2dee52018-09-28 10:58:28 -070043@Service
Luca Pretedce16f82016-11-22 13:11:56 -080044@Command(scope = "onos", name = "vpls",
45 description = "Manages the VPLS application")
46public class VplsCommand extends AbstractShellCommand {
Yi Tseng3069c612017-05-26 17:09:43 -070047 private static final Set<VplsState> CHANGING_STATE =
48 ImmutableSet.of(ADDING, REMOVING, UPDATING);
Luca Pretedce16f82016-11-22 13:11:56 -080049
50 // Color codes and style
51 private static final String BOLD = "\u001B[1m";
52 private static final String COLOR_ERROR = "\u001B[31m";
53 private static final String RESET = "\u001B[0m";
54
55 // Messages and string formatter
56 private static final String ENCAP_NOT_FOUND =
57 COLOR_ERROR + "Encapsulation type " + BOLD + "%s" + RESET +
58 COLOR_ERROR + " not found" + RESET;
59
60 private static final String IFACE_NOT_FOUND =
61 COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR +
62 " not found" + RESET;
63
64 private static final String IFACE_ALREADY_ASSOCIATED =
65 COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR +
66 " already associated to VPLS " + BOLD + "%s" + RESET +
67 COLOR_ERROR + "" + RESET;
68
Luca Prete8dbbea82016-12-07 18:10:10 -080069 private static final String INSERT_VPLS_NAME =
70 COLOR_ERROR + "Missing the " + BOLD + "VPLS name." + RESET +
71 COLOR_ERROR + " Specifying a VPLS name is mandatory." +
72 RESET;
73
74 private static final String INSERT_ENCAP_TYPE =
75 COLOR_ERROR + "Missing the " + BOLD + "encapsulation type." +
76 RESET + COLOR_ERROR + " Encapsulation type is mandatory." +
77 RESET;
78
79 private static final String INSERT_INTERFACE =
80 COLOR_ERROR + "Missing the " + BOLD + "interface name." +
81 RESET + COLOR_ERROR + " Specifying an interface name is" +
82 " mandatory." + RESET;
83
Luca Pretedce16f82016-11-22 13:11:56 -080084 private static final String SEPARATOR = "----------------";
85
86 private static final String VPLS_ALREADY_EXISTS =
87 COLOR_ERROR + "VPLS " + BOLD + "%s" + RESET + COLOR_ERROR +
88 " already exists" + RESET;
89
90 private static final String VPLS_COMMAND_NOT_FOUND =
91 COLOR_ERROR + "VPLS command " + BOLD + "%s" + RESET + COLOR_ERROR +
92 " not found" + RESET;
93
94 private static final String VPLS_DISPLAY = "VPLS name: " + BOLD +
Yi Tsengf4e13e32017-03-30 15:38:39 -070095 "%s" + RESET + "\nAssociated interfaces: %s\nEncapsulation: %s\n" +
96 "State: %s";
Luca Pretedce16f82016-11-22 13:11:56 -080097
Luca Pretedce16f82016-11-22 13:11:56 -080098 private static final String VPLS_NOT_FOUND =
99 COLOR_ERROR + "VPLS " + BOLD + "%s" + RESET + COLOR_ERROR +
100 " not found" + RESET;
101
102 private static final String IFACE_NOT_ASSOCIATED =
103 COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR +
Yi Tsengf4e13e32017-03-30 15:38:39 -0700104 " cannot be removed from VPLS " + BOLD + "%s" + RESET + ".";
Luca Pretedce16f82016-11-22 13:11:56 -0800105
Ray Milkey06297ed2018-01-22 17:13:41 -0800106 protected Vpls vpls;
107 protected InterfaceService interfaceService;
Luca Pretedce16f82016-11-22 13:11:56 -0800108
Luca Prete8dbbea82016-12-07 18:10:10 -0800109 @Argument(index = 0, name = "command", description = "Command name (add-if|" +
Yi Tsengf4e13e32017-03-30 15:38:39 -0700110 "create|delete|list|rem-if|set-encap|show)",
Luca Pretedce16f82016-11-22 13:11:56 -0800111 required = true, multiValued = false)
112 String command = null;
113
114 @Argument(index = 1, name = "vplsName", description = "The name of the VPLS",
115 required = false, multiValued = false)
116 String vplsName = null;
117
Luca Prete8dbbea82016-12-07 18:10:10 -0800118 @Argument(index = 2, name = "optArg", description = "The interface name or" +
119 " the encapsulation type for set-encap",
Luca Pretedce16f82016-11-22 13:11:56 -0800120 required = false, multiValued = false)
121 String optArg = null;
122
123 @Override
Ray Milkey86ad7bb2018-09-27 12:32:28 -0700124 protected void doExecute() {
Yi Tsengf4e13e32017-03-30 15:38:39 -0700125 if (vpls == null) {
126 vpls = get(Vpls.class);
127 }
128 if (interfaceService == null) {
129 interfaceService = get(InterfaceService.class);
130 }
131
Luca Pretedce16f82016-11-22 13:11:56 -0800132 VplsCommandEnum enumCommand = VplsCommandEnum.enumFromString(command);
133 if (enumCommand != null) {
134 switch (enumCommand) {
135 case ADD_IFACE:
136 addIface(vplsName, optArg);
137 break;
Luca Pretedce16f82016-11-22 13:11:56 -0800138 case CREATE:
139 create(vplsName);
140 break;
141 case DELETE:
142 delete(vplsName);
143 break;
144 case LIST:
145 list();
146 break;
147 case REMOVE_IFACE:
148 removeIface(vplsName, optArg);
149 break;
150 case SET_ENCAP:
151 setEncap(vplsName, optArg);
152 break;
153 case SHOW:
154 show(vplsName);
155 break;
Yi Tsengf4e13e32017-03-30 15:38:39 -0700156 case CLEAN:
157 cleanVpls();
158 break;
Luca Pretedce16f82016-11-22 13:11:56 -0800159 default:
160 print(VPLS_COMMAND_NOT_FOUND, command);
161 }
Luca Prete8dbbea82016-12-07 18:10:10 -0800162 } else {
163 print(VPLS_COMMAND_NOT_FOUND, command);
Luca Pretedce16f82016-11-22 13:11:56 -0800164 }
165 }
166
167 /**
168 * Adds an inteterface to a VPLS.
169 *
170 * @param vplsName the name of the VLPS
171 * @param ifaceName the name of the interface to add
172 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700173 protected void addIface(String vplsName, String ifaceName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800174 if (vplsName == null) {
175 print(INSERT_VPLS_NAME);
176 return;
177 }
178 if (ifaceName == null) {
179 print(INSERT_INTERFACE);
180 return;
181 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700182
183 Interface iface = getInterface(ifaceName);
184 VplsData vplsData = vpls.getVpls(vplsName);
185
186 if (vplsData == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800187 print(VPLS_NOT_FOUND, vplsName);
188 return;
189 }
Yi Tseng3069c612017-05-26 17:09:43 -0700190 if (CHANGING_STATE.contains(vplsData.state())) {
191 // when a VPLS is updating, we shouldn't try modify it.
192 print("VPLS %s still updating, please wait it finished", vplsData.name());
193 return;
194 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700195 if (iface == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800196 print(IFACE_NOT_FOUND, ifaceName);
197 return;
198 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700199 if (isIfaceAssociated(iface)) {
Luca Pretedce16f82016-11-22 13:11:56 -0800200 print(IFACE_ALREADY_ASSOCIATED,
Yi Tsengf4e13e32017-03-30 15:38:39 -0700201 ifaceName, getVplsByInterface(iface).name());
Luca Pretedce16f82016-11-22 13:11:56 -0800202 return;
203 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700204 vpls.addInterface(vplsData, iface);
Luca Pretedce16f82016-11-22 13:11:56 -0800205 }
206
207 /**
208 * Creates a new VPLS.
209 *
210 * @param vplsName the name of the VLPS
211 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700212 protected void create(String vplsName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800213 if (vplsName == null || vplsName.isEmpty()) {
214 print(INSERT_VPLS_NAME);
215 return;
216 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700217 VplsData vplsData = vpls.getVpls(vplsName);
218 if (vplsData != null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800219 print(VPLS_ALREADY_EXISTS, vplsName);
220 return;
221 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700222 vpls.createVpls(vplsName, EncapsulationType.NONE);
Luca Pretedce16f82016-11-22 13:11:56 -0800223 }
224
225 /**
226 * Deletes a VPLS.
227 *
228 * @param vplsName the name of the VLPS
229 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700230 protected void delete(String vplsName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800231 if (vplsName == null) {
232 print(INSERT_VPLS_NAME);
233 return;
234 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700235 VplsData vplsData = vpls.getVpls(vplsName);
236 if (vplsData == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800237 print(VPLS_NOT_FOUND, vplsName);
238 return;
239 }
Yi Tseng3069c612017-05-26 17:09:43 -0700240 if (CHANGING_STATE.contains(vplsData.state())) {
241 // when a VPLS is updating, we shouldn't try modify it.
242 print("VPLS %s still updating, please wait it finished", vplsData.name());
243 return;
244 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700245 vpls.removeVpls(vplsData);
Luca Pretedce16f82016-11-22 13:11:56 -0800246 }
247
248 /**
249 * Lists the configured VPLSs.
250 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700251 protected void list() {
252 List<String> vplsNames = vpls.getAllVpls().stream()
253 .map(VplsData::name)
254 .collect(Collectors.toList());
Luca Pretedce16f82016-11-22 13:11:56 -0800255 Collections.sort(vplsNames);
256
Luca Pretedce16f82016-11-22 13:11:56 -0800257 vplsNames.forEach(vpls -> {
258 print(vpls);
259 });
260 }
261
262 /**
263 * Removes an interface from a VPLS.
264 *
265 * @param vplsName the name of the VLPS
266 * @param ifaceName the name of the interface to remove
267 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700268 protected void removeIface(String vplsName, String ifaceName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800269 if (vplsName == null) {
270 print(INSERT_VPLS_NAME);
271 return;
272 }
273 if (ifaceName == null) {
274 print(INSERT_INTERFACE);
275 return;
276 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700277 VplsData vplsData = vpls.getVpls(vplsName);
278 Interface iface = getInterface(ifaceName);
279 if (vplsData == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800280 print(VPLS_NOT_FOUND, vplsName);
281 return;
282 }
Yi Tseng3069c612017-05-26 17:09:43 -0700283 if (CHANGING_STATE.contains(vplsData.state())) {
284 // when a VPLS is updating, we shouldn't try modify it.
285 print("VPLS %s still updating, please wait it finished", vplsData.name());
286 return;
287 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700288 if (iface == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800289 print(IFACE_NOT_FOUND, ifaceName);
290 return;
291 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700292 if (!vplsData.interfaces().contains(iface)) {
293 print(IFACE_NOT_ASSOCIATED, ifaceName, vplsName);
Luca Pretedce16f82016-11-22 13:11:56 -0800294 return;
295 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700296 vpls.removeInterface(vplsData, iface);
Luca Pretedce16f82016-11-22 13:11:56 -0800297 }
298
299 /**
300 * Sets the encapsulation type for a VPLS.
301 *
302 * @param vplsName the name of the VPLS
303 * @param encap the encapsulation type
304 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700305 protected void setEncap(String vplsName, String encap) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800306 if (vplsName == null) {
307 print(INSERT_VPLS_NAME);
308 return;
309 }
310 if (encap == null) {
311 print(INSERT_ENCAP_TYPE);
312 return;
313 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700314 VplsData vplsData = vpls.getVpls(vplsName);
315 if (vplsData == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800316 print(VPLS_NOT_FOUND, vplsName);
317 return;
318 }
319 EncapsulationType encapType = EncapsulationType.enumFromString(encap);
320 if (encapType.equals(EncapsulationType.NONE) &&
321 !encapType.toString().equals(encap)) {
322 print(ENCAP_NOT_FOUND, encap);
323 return;
324 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700325 vpls.setEncapsulationType(vplsData, encapType);
Luca Pretedce16f82016-11-22 13:11:56 -0800326 }
327
328 /**
329 * Shows the details of one or more VPLSs.
330 *
331 * @param vplsName the name of the VPLS
332 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700333 protected void show(String vplsName) {
Luca Pretedce16f82016-11-22 13:11:56 -0800334 if (!isNullOrEmpty(vplsName)) {
335 // A VPLS name is provided. Check first if the VPLS exists
Yi Tsengf4e13e32017-03-30 15:38:39 -0700336 VplsData vplsData = vpls.getVpls(vplsName);
337 if (vplsData != null) {
338 Set<String> ifaceNames = vplsData.interfaces().stream()
339 .map(Interface::name)
340 .collect(Collectors.toSet());
Luca Pretedce16f82016-11-22 13:11:56 -0800341 print(VPLS_DISPLAY,
342 vplsName,
Yi Tsengf4e13e32017-03-30 15:38:39 -0700343 ifaceNames,
344 vplsData.encapsulationType().toString(),
345 vplsData.state());
Luca Pretedce16f82016-11-22 13:11:56 -0800346 } else {
347 print(VPLS_NOT_FOUND, vplsName);
348 }
349 } else {
Yi Tsengf4e13e32017-03-30 15:38:39 -0700350 Collection<VplsData> vplses = vpls.getAllVpls();
Luca Pretedce16f82016-11-22 13:11:56 -0800351 // No VPLS names are provided. Display all VPLSs configured
Luca Prete8dbbea82016-12-07 18:10:10 -0800352 print(SEPARATOR);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700353 vplses.forEach(vplsData -> {
354 Set<String> ifaceNames = vplsData.interfaces().stream()
355 .map(Interface::name)
356 .collect(Collectors.toSet());
Luca Pretedce16f82016-11-22 13:11:56 -0800357 print(VPLS_DISPLAY,
Yi Tsengf4e13e32017-03-30 15:38:39 -0700358 vplsData.name(),
359 ifaceNames,
360 vplsData.encapsulationType().toString(),
361 vplsData.state());
Luca Pretedce16f82016-11-22 13:11:56 -0800362 print(SEPARATOR);
363 });
364 }
365 }
366
367 /**
Yi Tsengf4e13e32017-03-30 15:38:39 -0700368 * Remove all VPLS.
Luca Pretedce16f82016-11-22 13:11:56 -0800369 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700370 protected void cleanVpls() {
371 vpls.removeAllVpls();
Luca Pretedce16f82016-11-22 13:11:56 -0800372 }
373
Luca Pretedce16f82016-11-22 13:11:56 -0800374
375 /**
376 * States if an interface is already associated to a VPLS.
377 *
Yi Tsengf4e13e32017-03-30 15:38:39 -0700378 * @param iface the interface
Luca Pretedce16f82016-11-22 13:11:56 -0800379 * @return true if the interface is already associated to a VPLS; false
380 * otherwise
381 */
Ray Milkey06297ed2018-01-22 17:13:41 -0800382 private boolean isIfaceAssociated(Interface iface) {
Yi Tsengf4e13e32017-03-30 15:38:39 -0700383 return vpls.getAllVpls()
Luca Pretedce16f82016-11-22 13:11:56 -0800384 .stream()
Yi Tsengf4e13e32017-03-30 15:38:39 -0700385 .map(VplsData::interfaces)
386 .flatMap(Collection::stream)
387 .anyMatch(iface::equals);
Luca Pretedce16f82016-11-22 13:11:56 -0800388 }
389
390 /**
Yi Tsengf4e13e32017-03-30 15:38:39 -0700391 * Gets a network interface by given interface name.
Luca Pretedce16f82016-11-22 13:11:56 -0800392 *
Yi Tsengf4e13e32017-03-30 15:38:39 -0700393 * @param interfaceName the interface name
394 * @return the network interface
Luca Pretedce16f82016-11-22 13:11:56 -0800395 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700396 private Interface getInterface(String interfaceName) {
397 // FIXME: only returns first interface it found
398 // multiple interface with same name not support
399 return interfaceService.getInterfaces().stream()
400 .filter(iface -> iface.name().equals(interfaceName))
401 .findFirst()
402 .orElse(null);
Luca Pretedce16f82016-11-22 13:11:56 -0800403 }
404
405 /**
Yi Tsengf4e13e32017-03-30 15:38:39 -0700406 * Gets a VPLS related to the network interface.
Luca Pretedce16f82016-11-22 13:11:56 -0800407 *
Yi Tsengf4e13e32017-03-30 15:38:39 -0700408 * @param iface the network interface
409 * @return the VPLS related to the network interface
Luca Pretedce16f82016-11-22 13:11:56 -0800410 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700411 private VplsData getVplsByInterface(Interface iface) {
412 return vpls.getAllVpls().stream()
413 .filter(vplsData -> vplsData.interfaces().contains(iface))
414 .findFirst()
415 .orElse(null);
Luca Pretedce16f82016-11-22 13:11:56 -0800416 }
417}