blob: bf256688e78302cf5afe08427c65ab38485a2f8e [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;
Luca Pretedce16f82016-11-22 13:11:56 -080019import org.apache.karaf.shell.commands.Argument;
20import org.apache.karaf.shell.commands.Command;
21import org.onosproject.cli.AbstractShellCommand;
22import org.onosproject.incubator.net.intf.Interface;
Yi Tsengf4e13e32017-03-30 15:38:39 -070023import org.onosproject.incubator.net.intf.InterfaceService;
Luca Pretedce16f82016-11-22 13:11:56 -080024import org.onosproject.net.EncapsulationType;
Yi Tsengf4e13e32017-03-30 15:38:39 -070025import org.onosproject.vpls.api.VplsData;
26import org.onosproject.vpls.api.Vpls;
Yi Tseng3069c612017-05-26 17:09:43 -070027import org.onosproject.vpls.api.VplsData.VplsState;
Luca Pretedce16f82016-11-22 13:11:56 -080028
Yi Tsengf4e13e32017-03-30 15:38:39 -070029import java.util.Collection;
Luca Pretedce16f82016-11-22 13:11:56 -080030import java.util.Collections;
31import java.util.List;
Luca Pretedce16f82016-11-22 13:11:56 -080032import java.util.Set;
Yi Tsengf4e13e32017-03-30 15:38:39 -070033import java.util.stream.Collectors;
Luca Pretedce16f82016-11-22 13:11:56 -080034
35import static com.google.common.base.Strings.isNullOrEmpty;
Yi Tseng3069c612017-05-26 17:09:43 -070036import static org.onosproject.vpls.api.VplsData.VplsState.*;
Luca Pretedce16f82016-11-22 13:11:56 -080037
Yi Tsengf4e13e32017-03-30 15:38:39 -070038
Luca Pretedce16f82016-11-22 13:11:56 -080039/**
40 * CLI to interact with the VPLS application.
41 */
42@Command(scope = "onos", name = "vpls",
43 description = "Manages the VPLS application")
44public class VplsCommand extends AbstractShellCommand {
Yi Tseng3069c612017-05-26 17:09:43 -070045 private static final Set<VplsState> CHANGING_STATE =
46 ImmutableSet.of(ADDING, REMOVING, UPDATING);
Luca Pretedce16f82016-11-22 13:11:56 -080047
48 // Color codes and style
49 private static final String BOLD = "\u001B[1m";
50 private static final String COLOR_ERROR = "\u001B[31m";
51 private static final String RESET = "\u001B[0m";
52
53 // Messages and string formatter
54 private static final String ENCAP_NOT_FOUND =
55 COLOR_ERROR + "Encapsulation type " + BOLD + "%s" + RESET +
56 COLOR_ERROR + " not found" + RESET;
57
58 private static final String IFACE_NOT_FOUND =
59 COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR +
60 " not found" + RESET;
61
62 private static final String IFACE_ALREADY_ASSOCIATED =
63 COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR +
64 " already associated to VPLS " + BOLD + "%s" + RESET +
65 COLOR_ERROR + "" + RESET;
66
Luca Prete8dbbea82016-12-07 18:10:10 -080067 private static final String INSERT_VPLS_NAME =
68 COLOR_ERROR + "Missing the " + BOLD + "VPLS name." + RESET +
69 COLOR_ERROR + " Specifying a VPLS name is mandatory." +
70 RESET;
71
72 private static final String INSERT_ENCAP_TYPE =
73 COLOR_ERROR + "Missing the " + BOLD + "encapsulation type." +
74 RESET + COLOR_ERROR + " Encapsulation type is mandatory." +
75 RESET;
76
77 private static final String INSERT_INTERFACE =
78 COLOR_ERROR + "Missing the " + BOLD + "interface name." +
79 RESET + COLOR_ERROR + " Specifying an interface name is" +
80 " mandatory." + RESET;
81
Luca Pretedce16f82016-11-22 13:11:56 -080082 private static final String SEPARATOR = "----------------";
83
84 private static final String VPLS_ALREADY_EXISTS =
85 COLOR_ERROR + "VPLS " + BOLD + "%s" + RESET + COLOR_ERROR +
86 " already exists" + RESET;
87
88 private static final String VPLS_COMMAND_NOT_FOUND =
89 COLOR_ERROR + "VPLS command " + BOLD + "%s" + RESET + COLOR_ERROR +
90 " not found" + RESET;
91
92 private static final String VPLS_DISPLAY = "VPLS name: " + BOLD +
Yi Tsengf4e13e32017-03-30 15:38:39 -070093 "%s" + RESET + "\nAssociated interfaces: %s\nEncapsulation: %s\n" +
94 "State: %s";
Luca Pretedce16f82016-11-22 13:11:56 -080095
Luca Pretedce16f82016-11-22 13:11:56 -080096 private static final String VPLS_NOT_FOUND =
97 COLOR_ERROR + "VPLS " + BOLD + "%s" + RESET + COLOR_ERROR +
98 " not found" + RESET;
99
100 private static final String IFACE_NOT_ASSOCIATED =
101 COLOR_ERROR + "Interface " + BOLD + "%s" + RESET + COLOR_ERROR +
Yi Tsengf4e13e32017-03-30 15:38:39 -0700102 " cannot be removed from VPLS " + BOLD + "%s" + RESET + ".";
Luca Pretedce16f82016-11-22 13:11:56 -0800103
Yi Tsengf4e13e32017-03-30 15:38:39 -0700104 protected static Vpls vpls;
105 protected static InterfaceService interfaceService;
Luca Pretedce16f82016-11-22 13:11:56 -0800106
Luca Prete8dbbea82016-12-07 18:10:10 -0800107 @Argument(index = 0, name = "command", description = "Command name (add-if|" +
Yi Tsengf4e13e32017-03-30 15:38:39 -0700108 "create|delete|list|rem-if|set-encap|show)",
Luca Pretedce16f82016-11-22 13:11:56 -0800109 required = true, multiValued = false)
110 String command = null;
111
112 @Argument(index = 1, name = "vplsName", description = "The name of the VPLS",
113 required = false, multiValued = false)
114 String vplsName = null;
115
Luca Prete8dbbea82016-12-07 18:10:10 -0800116 @Argument(index = 2, name = "optArg", description = "The interface name or" +
117 " the encapsulation type for set-encap",
Luca Pretedce16f82016-11-22 13:11:56 -0800118 required = false, multiValued = false)
119 String optArg = null;
120
121 @Override
122 protected void execute() {
Yi Tsengf4e13e32017-03-30 15:38:39 -0700123 if (vpls == null) {
124 vpls = get(Vpls.class);
125 }
126 if (interfaceService == null) {
127 interfaceService = get(InterfaceService.class);
128 }
129
Luca Pretedce16f82016-11-22 13:11:56 -0800130 VplsCommandEnum enumCommand = VplsCommandEnum.enumFromString(command);
131 if (enumCommand != null) {
132 switch (enumCommand) {
133 case ADD_IFACE:
134 addIface(vplsName, optArg);
135 break;
Luca Pretedce16f82016-11-22 13:11:56 -0800136 case CREATE:
137 create(vplsName);
138 break;
139 case DELETE:
140 delete(vplsName);
141 break;
142 case LIST:
143 list();
144 break;
145 case REMOVE_IFACE:
146 removeIface(vplsName, optArg);
147 break;
148 case SET_ENCAP:
149 setEncap(vplsName, optArg);
150 break;
151 case SHOW:
152 show(vplsName);
153 break;
Yi Tsengf4e13e32017-03-30 15:38:39 -0700154 case CLEAN:
155 cleanVpls();
156 break;
Luca Pretedce16f82016-11-22 13:11:56 -0800157 default:
158 print(VPLS_COMMAND_NOT_FOUND, command);
159 }
Luca Prete8dbbea82016-12-07 18:10:10 -0800160 } else {
161 print(VPLS_COMMAND_NOT_FOUND, command);
Luca Pretedce16f82016-11-22 13:11:56 -0800162 }
163 }
164
165 /**
166 * Adds an inteterface to a VPLS.
167 *
168 * @param vplsName the name of the VLPS
169 * @param ifaceName the name of the interface to add
170 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700171 protected void addIface(String vplsName, String ifaceName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800172 if (vplsName == null) {
173 print(INSERT_VPLS_NAME);
174 return;
175 }
176 if (ifaceName == null) {
177 print(INSERT_INTERFACE);
178 return;
179 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700180
181 Interface iface = getInterface(ifaceName);
182 VplsData vplsData = vpls.getVpls(vplsName);
183
184 if (vplsData == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800185 print(VPLS_NOT_FOUND, vplsName);
186 return;
187 }
Yi Tseng3069c612017-05-26 17:09:43 -0700188 if (CHANGING_STATE.contains(vplsData.state())) {
189 // when a VPLS is updating, we shouldn't try modify it.
190 print("VPLS %s still updating, please wait it finished", vplsData.name());
191 return;
192 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700193 if (iface == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800194 print(IFACE_NOT_FOUND, ifaceName);
195 return;
196 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700197 if (isIfaceAssociated(iface)) {
Luca Pretedce16f82016-11-22 13:11:56 -0800198 print(IFACE_ALREADY_ASSOCIATED,
Yi Tsengf4e13e32017-03-30 15:38:39 -0700199 ifaceName, getVplsByInterface(iface).name());
Luca Pretedce16f82016-11-22 13:11:56 -0800200 return;
201 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700202 vpls.addInterface(vplsData, iface);
Luca Pretedce16f82016-11-22 13:11:56 -0800203 }
204
205 /**
206 * Creates a new VPLS.
207 *
208 * @param vplsName the name of the VLPS
209 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700210 protected void create(String vplsName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800211 if (vplsName == null || vplsName.isEmpty()) {
212 print(INSERT_VPLS_NAME);
213 return;
214 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700215 VplsData vplsData = vpls.getVpls(vplsName);
216 if (vplsData != null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800217 print(VPLS_ALREADY_EXISTS, vplsName);
218 return;
219 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700220 vpls.createVpls(vplsName, EncapsulationType.NONE);
Luca Pretedce16f82016-11-22 13:11:56 -0800221 }
222
223 /**
224 * Deletes a VPLS.
225 *
226 * @param vplsName the name of the VLPS
227 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700228 protected void delete(String vplsName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800229 if (vplsName == null) {
230 print(INSERT_VPLS_NAME);
231 return;
232 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700233 VplsData vplsData = vpls.getVpls(vplsName);
234 if (vplsData == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800235 print(VPLS_NOT_FOUND, vplsName);
236 return;
237 }
Yi Tseng3069c612017-05-26 17:09:43 -0700238 if (CHANGING_STATE.contains(vplsData.state())) {
239 // when a VPLS is updating, we shouldn't try modify it.
240 print("VPLS %s still updating, please wait it finished", vplsData.name());
241 return;
242 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700243 vpls.removeVpls(vplsData);
Luca Pretedce16f82016-11-22 13:11:56 -0800244 }
245
246 /**
247 * Lists the configured VPLSs.
248 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700249 protected void list() {
250 List<String> vplsNames = vpls.getAllVpls().stream()
251 .map(VplsData::name)
252 .collect(Collectors.toList());
Luca Pretedce16f82016-11-22 13:11:56 -0800253 Collections.sort(vplsNames);
254
Luca Pretedce16f82016-11-22 13:11:56 -0800255 vplsNames.forEach(vpls -> {
256 print(vpls);
257 });
258 }
259
260 /**
261 * Removes an interface from a VPLS.
262 *
263 * @param vplsName the name of the VLPS
264 * @param ifaceName the name of the interface to remove
265 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700266 protected void removeIface(String vplsName, String ifaceName) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800267 if (vplsName == null) {
268 print(INSERT_VPLS_NAME);
269 return;
270 }
271 if (ifaceName == null) {
272 print(INSERT_INTERFACE);
273 return;
274 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700275 VplsData vplsData = vpls.getVpls(vplsName);
276 Interface iface = getInterface(ifaceName);
277 if (vplsData == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800278 print(VPLS_NOT_FOUND, vplsName);
279 return;
280 }
Yi Tseng3069c612017-05-26 17:09:43 -0700281 if (CHANGING_STATE.contains(vplsData.state())) {
282 // when a VPLS is updating, we shouldn't try modify it.
283 print("VPLS %s still updating, please wait it finished", vplsData.name());
284 return;
285 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700286 if (iface == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800287 print(IFACE_NOT_FOUND, ifaceName);
288 return;
289 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700290 if (!vplsData.interfaces().contains(iface)) {
291 print(IFACE_NOT_ASSOCIATED, ifaceName, vplsName);
Luca Pretedce16f82016-11-22 13:11:56 -0800292 return;
293 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700294 vpls.removeInterface(vplsData, iface);
Luca Pretedce16f82016-11-22 13:11:56 -0800295 }
296
297 /**
298 * Sets the encapsulation type for a VPLS.
299 *
300 * @param vplsName the name of the VPLS
301 * @param encap the encapsulation type
302 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700303 protected void setEncap(String vplsName, String encap) {
Luca Prete8dbbea82016-12-07 18:10:10 -0800304 if (vplsName == null) {
305 print(INSERT_VPLS_NAME);
306 return;
307 }
308 if (encap == null) {
309 print(INSERT_ENCAP_TYPE);
310 return;
311 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700312 VplsData vplsData = vpls.getVpls(vplsName);
313 if (vplsData == null) {
Luca Pretedce16f82016-11-22 13:11:56 -0800314 print(VPLS_NOT_FOUND, vplsName);
315 return;
316 }
317 EncapsulationType encapType = EncapsulationType.enumFromString(encap);
318 if (encapType.equals(EncapsulationType.NONE) &&
319 !encapType.toString().equals(encap)) {
320 print(ENCAP_NOT_FOUND, encap);
321 return;
322 }
Yi Tsengf4e13e32017-03-30 15:38:39 -0700323 vpls.setEncapsulationType(vplsData, encapType);
Luca Pretedce16f82016-11-22 13:11:56 -0800324 }
325
326 /**
327 * Shows the details of one or more VPLSs.
328 *
329 * @param vplsName the name of the VPLS
330 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700331 protected void show(String vplsName) {
Luca Pretedce16f82016-11-22 13:11:56 -0800332 if (!isNullOrEmpty(vplsName)) {
333 // A VPLS name is provided. Check first if the VPLS exists
Yi Tsengf4e13e32017-03-30 15:38:39 -0700334 VplsData vplsData = vpls.getVpls(vplsName);
335 if (vplsData != null) {
336 Set<String> ifaceNames = vplsData.interfaces().stream()
337 .map(Interface::name)
338 .collect(Collectors.toSet());
Luca Pretedce16f82016-11-22 13:11:56 -0800339 print(VPLS_DISPLAY,
340 vplsName,
Yi Tsengf4e13e32017-03-30 15:38:39 -0700341 ifaceNames,
342 vplsData.encapsulationType().toString(),
343 vplsData.state());
Luca Pretedce16f82016-11-22 13:11:56 -0800344 } else {
345 print(VPLS_NOT_FOUND, vplsName);
346 }
347 } else {
Yi Tsengf4e13e32017-03-30 15:38:39 -0700348 Collection<VplsData> vplses = vpls.getAllVpls();
Luca Pretedce16f82016-11-22 13:11:56 -0800349 // No VPLS names are provided. Display all VPLSs configured
Luca Prete8dbbea82016-12-07 18:10:10 -0800350 print(SEPARATOR);
Yi Tsengf4e13e32017-03-30 15:38:39 -0700351 vplses.forEach(vplsData -> {
352 Set<String> ifaceNames = vplsData.interfaces().stream()
353 .map(Interface::name)
354 .collect(Collectors.toSet());
Luca Pretedce16f82016-11-22 13:11:56 -0800355 print(VPLS_DISPLAY,
Yi Tsengf4e13e32017-03-30 15:38:39 -0700356 vplsData.name(),
357 ifaceNames,
358 vplsData.encapsulationType().toString(),
359 vplsData.state());
Luca Pretedce16f82016-11-22 13:11:56 -0800360 print(SEPARATOR);
361 });
362 }
363 }
364
365 /**
Yi Tsengf4e13e32017-03-30 15:38:39 -0700366 * Remove all VPLS.
Luca Pretedce16f82016-11-22 13:11:56 -0800367 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700368 protected void cleanVpls() {
369 vpls.removeAllVpls();
Luca Pretedce16f82016-11-22 13:11:56 -0800370 }
371
Luca Pretedce16f82016-11-22 13:11:56 -0800372
373 /**
374 * States if an interface is already associated to a VPLS.
375 *
Yi Tsengf4e13e32017-03-30 15:38:39 -0700376 * @param iface the interface
Luca Pretedce16f82016-11-22 13:11:56 -0800377 * @return true if the interface is already associated to a VPLS; false
378 * otherwise
379 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700380 private static boolean isIfaceAssociated(Interface iface) {
381 return vpls.getAllVpls()
Luca Pretedce16f82016-11-22 13:11:56 -0800382 .stream()
Yi Tsengf4e13e32017-03-30 15:38:39 -0700383 .map(VplsData::interfaces)
384 .flatMap(Collection::stream)
385 .anyMatch(iface::equals);
Luca Pretedce16f82016-11-22 13:11:56 -0800386 }
387
388 /**
Yi Tsengf4e13e32017-03-30 15:38:39 -0700389 * Gets a network interface by given interface name.
Luca Pretedce16f82016-11-22 13:11:56 -0800390 *
Yi Tsengf4e13e32017-03-30 15:38:39 -0700391 * @param interfaceName the interface name
392 * @return the network interface
Luca Pretedce16f82016-11-22 13:11:56 -0800393 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700394 private Interface getInterface(String interfaceName) {
395 // FIXME: only returns first interface it found
396 // multiple interface with same name not support
397 return interfaceService.getInterfaces().stream()
398 .filter(iface -> iface.name().equals(interfaceName))
399 .findFirst()
400 .orElse(null);
Luca Pretedce16f82016-11-22 13:11:56 -0800401 }
402
403 /**
Yi Tsengf4e13e32017-03-30 15:38:39 -0700404 * Gets a VPLS related to the network interface.
Luca Pretedce16f82016-11-22 13:11:56 -0800405 *
Yi Tsengf4e13e32017-03-30 15:38:39 -0700406 * @param iface the network interface
407 * @return the VPLS related to the network interface
Luca Pretedce16f82016-11-22 13:11:56 -0800408 */
Yi Tsengf4e13e32017-03-30 15:38:39 -0700409 private VplsData getVplsByInterface(Interface iface) {
410 return vpls.getAllVpls().stream()
411 .filter(vplsData -> vplsData.interfaces().contains(iface))
412 .findFirst()
413 .orElse(null);
Luca Pretedce16f82016-11-22 13:11:56 -0800414 }
415}