blob: a3d0b9f05fe4348badc7c664248c57061131bbb2 [file] [log] [blame]
Thomas Vachuska7d693f52014-10-21 19:17:57 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
Thomas Vachuska7d693f52014-10-21 19:17:57 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska7d693f52014-10-21 19:17:57 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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
14 * limitations under the License.
Thomas Vachuska7d693f52014-10-21 19:17:57 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.cli.net;
tomf5c9d922014-10-03 15:22:03 -070017
Luca Prete5db2e872016-12-07 18:31:00 -080018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.ObjectMapper;
20import com.fasterxml.jackson.databind.node.ArrayNode;
21import com.fasterxml.jackson.databind.node.ObjectNode;
22import com.google.common.base.Strings;
23import com.google.common.collect.Lists;
24import com.google.common.collect.Sets;
25import org.apache.commons.lang.StringUtils;
tomf5c9d922014-10-03 15:22:03 -070026import org.apache.karaf.shell.commands.Command;
Brian O'Connorfe0f4b12014-10-30 21:19:02 -070027import org.apache.karaf.shell.commands.Option;
Carolina Fernandezfa56d142016-11-14 01:13:26 +010028import org.onlab.util.StringFilter;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -080029import org.onlab.util.Tools;
Brian O'Connorabafb502014-12-02 22:26:20 -080030import org.onosproject.cli.AbstractShellCommand;
Luca Prete5db2e872016-12-07 18:31:00 -080031import org.onosproject.net.ConnectPoint;
32import org.onosproject.net.FilteredConnectPoint;
33import org.onosproject.net.flow.TrafficSelector;
34import org.onosproject.net.flow.criteria.Criterion;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.intent.ConnectivityIntent;
Pavlin Radoslavovaab51a32014-12-08 11:07:38 -080036import org.onosproject.net.intent.HostToHostIntent;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.net.intent.Intent;
38import org.onosproject.net.intent.IntentService;
39import org.onosproject.net.intent.IntentState;
40import org.onosproject.net.intent.LinkCollectionIntent;
41import org.onosproject.net.intent.MultiPointToSinglePointIntent;
Rimon Ashkenazyf0699702016-01-17 19:28:49 +020042import org.onosproject.net.intent.OpticalCircuitIntent;
43import org.onosproject.net.intent.OpticalConnectivityIntent;
Rimon Ashkenazy27438ff2016-03-22 15:57:45 +020044import org.onosproject.net.intent.OpticalOduIntent;
Brian O'Connorabafb502014-12-02 22:26:20 -080045import org.onosproject.net.intent.PathIntent;
46import org.onosproject.net.intent.PointToPointIntent;
47import org.onosproject.net.intent.SinglePointToMultiPointIntent;
Thomas Vachuska6ce73042014-10-21 10:01:49 -070048
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -080049import static com.google.common.base.MoreObjects.firstNonNull;
50import static java.lang.String.format;
51import static org.apache.commons.lang3.text.WordUtils.uncapitalize;
52
Luca Prete5db2e872016-12-07 18:31:00 -080053import java.util.ArrayList;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -080054import java.util.HashMap;
Luca Prete5db2e872016-12-07 18:31:00 -080055import java.util.List;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -080056import java.util.Map;
Luca Prete5db2e872016-12-07 18:31:00 -080057import java.util.Set;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -080058import java.util.stream.Collectors;
tomf5c9d922014-10-03 15:22:03 -070059
60/**
61 * Lists the inventory of intents and their states.
62 */
63@Command(scope = "onos", name = "intents",
64 description = "Lists the inventory of intents and their states")
65public class IntentsListCommand extends AbstractShellCommand {
66
Luca Prete5db2e872016-12-07 18:31:00 -080067 // Color codes and style
68 private static final String BOLD = "\u001B[1m";
69 private static final String RESET = "\u001B[0m";
70
71 // Messages and string formatter
72 private static final String APP_ID = BOLD + "Application Id:" + RESET + " %s";
73
74 private static final String COMMON_SELECTOR = BOLD + "Common ingress " +
75 "selector:" + RESET + " %s";
76
77 private static final String CP = BOLD + "Connect Point:" + RESET + " %s";
78
79 private static final String CONSTRAINTS = BOLD + "Constraints:" + RESET + " %s";
80
81 private static final String DST = BOLD + "Destination " + RESET;
82
83 private static final String EGRESS = BOLD + "Egress ";
84
85 private static final String FILTERED_CPS = "connect points and individual selectors" + RESET;
86
87 private static final String HOST = "host:" + RESET + " %s";
88
89 private static final String ID = BOLD + "Id:" + RESET + " %s";
90
91 private static final String INHERITED = "Inherited";
92
93 private static final String INGRESS = BOLD + "Ingress ";
94
95 private static final String INDENTATION = " -> ";
96
97 private static final String INSTALLABLE = BOLD + "Installable:" + RESET + " %s";
98
99 private static final String KEY = BOLD + "Key:" + RESET + " %s";
100
101 private static final String RESOURCES = BOLD + "Resources:" + RESET + " %s";
102
103 private static final String SELECTOR = BOLD + "Selector:" + RESET + " %s";
104
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800105 private static final String SEPARATOR = StringUtils.repeat("-", 172);
Luca Prete5db2e872016-12-07 18:31:00 -0800106
107 private static final String SPACE = " ";
108
109 private static final String SRC = BOLD + "Source ";
110
111 private static final String STATE = BOLD + "State:" + RESET + " %s";
112
113 private static final String TREATMENT = BOLD + "Treatment:" + RESET + " %s";
114
115 private static final String TYPE = BOLD + "Intent type:" + RESET + " %s";
116
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800117 /**
118 * {@value #SUMMARY_TITLES}.
119 */
Luca Prete5db2e872016-12-07 18:31:00 -0800120 private static final String SUMMARY_TITLES =
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800121 BOLD + format(
Luca Prete5db2e872016-12-07 18:31:00 -0800122 "\n%1s%21s%14s%14s%14s%14s%14s%14s%14s%14s%14s%14s",
123 "Intent type",
124 "Total",
125 "Installed",
126 "Withdrawn",
127 "Failed",
128 "InstallReq",
129 "Compiling",
130 "Installing",
131 "Recompiling",
132 "WithdrawReq",
133 "Withdrawing",
134 "UnknownState") +
135 RESET;
136
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800137 @Option(name = "-i", aliases = "--installable",
138 description = "Output Installable Intents",
Brian O'Connorfe0f4b12014-10-30 21:19:02 -0700139 required = false, multiValued = false)
140 private boolean showInstallable = false;
141
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800142 @Option(name = "-s", aliases = "--summary",
143 description = "Intents summary",
144 required = false, multiValued = false)
145 private boolean intentsSummary = false;
Brian O'Connorfe0f4b12014-10-30 21:19:02 -0700146
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800147 @Option(name = "-m", aliases = "--mini-summary",
148 description = "Intents mini summary",
149 required = false, multiValued = false)
150 private boolean miniSummary = false;
151
Jonathan Hart34f1e382015-02-24 16:52:23 -0800152 @Option(name = "-p", aliases = "--pending",
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100153 description = "Show information about pending intents",
Jonathan Hart34f1e382015-02-24 16:52:23 -0800154 required = false, multiValued = false)
155 private boolean pending = false;
156
Carolina Fernandez0b1449d2016-12-04 13:30:36 +0100157 @Option(name = "-d", aliases = "--details",
158 description = "Show details for intents, filtered by ID",
159 required = false, multiValued = true)
160 private List<String> intentIds = new ArrayList<>();
161
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100162 @Option(name = "-f", aliases = "--filter",
Yuta HIGUCHIfadb9a32017-01-13 09:33:10 -0800163 description = "Filter intents by specific keyword",
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100164 required = false, multiValued = true)
165 private List<String> filter = new ArrayList<>();
166
Carolina Fernandez0b1449d2016-12-04 13:30:36 +0100167 @Option(name = "-r", aliases = "--remove",
168 description = "Remove and purge intents by specific keyword",
169 required = false, multiValued = false)
170 private String remove = null;
171
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100172 private StringFilter contentFilter;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800173 private IntentService service;
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100174
tomf5c9d922014-10-03 15:22:03 -0700175 @Override
176 protected void execute() {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800177 service = get(IntentService.class);
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100178 contentFilter = new StringFilter(filter, StringFilter.Strategy.AND);
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800179
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800180 Iterable<Intent> intents;
181 if (pending) {
182 intents = service.getPending();
183 } else {
184 intents = service.getIntents();
185 }
186
Carolina Fernandez0b1449d2016-12-04 13:30:36 +0100187 // Remove intents
188 if (remove != null && !remove.isEmpty()) {
189 filter.add(remove);
190 contentFilter = new StringFilter(filter, StringFilter.Strategy.AND);
191 IntentRemoveCommand intentRemoveCmd = new IntentRemoveCommand();
192 if (!remove.isEmpty()) {
193 intentRemoveCmd.purgeIntentsInteractive(filterIntents(service));
194 }
195 return;
196 }
197
198 // Show detailed intents
199 if (!intentIds.isEmpty()) {
200 IntentDetailsCommand intentDetailsCmd = new IntentDetailsCommand();
201 intentDetailsCmd.detailIntents(intentIds);
202 return;
203 }
204
205 // Show brief intents
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800206 if (intentsSummary || miniSummary) {
207 Map<String, IntentSummary> summarized = summarize(intents);
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800208 if (outputJson()) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800209 ObjectNode summaries = mapper().createObjectNode();
210 summarized.forEach((n, s) -> summaries.set(uncapitalize(n), s.json(mapper())));
211 print("%s", summaries);
212 } else if (miniSummary) {
213 StringBuilder builder = new StringBuilder();
214 builder.append(summarized.remove("All").miniSummary());
215 summarized.values().forEach(s -> builder.append(s.miniSummary()));
216 print("%s", builder.toString());
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800217 } else {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800218 StringBuilder builder = new StringBuilder();
219 builder.append(SUMMARY_TITLES);
220 builder.append('\n').append(SEPARATOR);
221 builder.append(summarized.remove("All").summary());
222 summarized.values().forEach(s -> builder.append(s.summary()));
223 print("%s", builder.toString());
Ray Milkey740c8a32015-03-17 13:41:03 -0700224 }
Jonathan Hart34f1e382015-02-24 16:52:23 -0800225 return;
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800226 }
227
Carolina Fernandez0b1449d2016-12-04 13:30:36 +0100228 // JSON or default output
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700229 if (outputJson()) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800230 print("%s", json(intents));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700231 } else {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800232 for (Intent intent : intents) {
233 IntentState state = service.getIntentState(intent.key());
234 StringBuilder intentFormat = fullFormat(intent, state);
235 StringBuilder detailsIntentFormat = detailsFormat(intent, state);
236 String formatted = intentFormat.append(detailsIntentFormat).toString();
237 if (contentFilter.filter(formatted)) {
238 print("%s\n", formatted);
239 }
240 }
tomf5c9d922014-10-03 15:22:03 -0700241 }
242 }
243
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800244 /**
Carolina Fernandez0b1449d2016-12-04 13:30:36 +0100245 * Filter a given list of intents based on the existing content filter.
246 *
247 * @param service IntentService object
248 * @return further filtered list of intents
249 */
250 private List<Intent> filterIntents(IntentService service) {
251 return filterIntents(service.getIntents());
252 }
253
254 /**
255 * Filter a given list of intents based on the existing content filter.
256 *
257 * @param intents Iterable of intents
258 * @return further filtered list of intents
259 */
260 private List<Intent> filterIntents(Iterable<Intent> intents) {
261 return Tools.stream(intents)
262 .filter(i -> contentFilter.filter(i)).collect(Collectors.toList());
263 }
264
265 /**
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800266 * Internal local class to keep track of a single type Intent summary.
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800267 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800268 private class IntentSummary {
269 private final String intentType;
270 private int total = 0;
271 private int installReq = 0;
272 private int compiling = 0;
273 private int installing = 0;
274 private int installed = 0;
275 private int recompiling = 0;
276 private int withdrawReq = 0;
277 private int withdrawing = 0;
278 private int withdrawn = 0;
279 private int failed = 0;
280 private int unknownState = 0;
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800281
282 /**
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800283 * Creates empty {@link IntentSummary} for specified {@code intentType}.
284 *
285 * @param intentType the string describing the Intent type
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800286 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800287 IntentSummary(String intentType) {
288 this.intentType = intentType;
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800289 }
290
291 /**
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800292 * Creates {@link IntentSummary} initialized with given {@code intent}.
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800293 *
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800294 * @param intent to initialize with
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800295 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800296 IntentSummary(Intent intent) {
297 // remove "Intent" from intentType label
298 this(intentType(intent));
Carolina Fernandez0b1449d2016-12-04 13:30:36 +0100299 if (contentFilter.filter(intent)) {
300 update(service.getIntentState(intent.key()));
301 }
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800302 }
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800303
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800304 // for identity element, when reducing
305 IntentSummary() {
306 this.intentType = null;
307 }
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800308
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800309 /**
310 * Updates the Intent Summary.
311 *
312 * @param intentState the state of the intent
313 */
314 void update(IntentState intentState) {
315 total++;
316 switch (intentState) {
317 case INSTALL_REQ:
318 installReq++;
319 break;
320 case COMPILING:
321 compiling++;
322 break;
323 case INSTALLING:
324 installing++;
325 break;
326 case INSTALLED:
327 installed++;
328 break;
329 case RECOMPILING:
330 recompiling++;
331 break;
332 case WITHDRAW_REQ:
333 withdrawReq++;
334 break;
335 case WITHDRAWING:
336 withdrawing++;
337 break;
338 case WITHDRAWN:
339 withdrawn++;
340 break;
341 case FAILED:
342 failed++;
343 break;
344 default:
345 unknownState++;
346 break;
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800347 }
348 }
349
350 /**
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800351 * Prints the Intent Summary.
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800352 *
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800353 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800354 StringBuilder summary() {
Luca Prete5db2e872016-12-07 18:31:00 -0800355 StringBuilder builder = new StringBuilder();
Luca Prete5db2e872016-12-07 18:31:00 -0800356
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800357 builder.append(format(
358 "\n%1s%s%14d%14d%14d%14d%14d%14d%14d%14d%14d%14d",
359 BOLD + intentType + RESET,
360 Strings.padStart(String.valueOf(total),
361 (32 - intentType.length()),
362 ' '),
363 installed,
364 withdrawn,
365 failed,
366 installReq,
367 compiling,
368 installing,
369 recompiling,
370 withdrawReq,
371 withdrawing,
372 unknownState));
373 builder.append('\n').append(SEPARATOR);
374
375 return builder;
376 }
377
378 StringBuilder miniSummary() {
379 StringBuilder builder = new StringBuilder();
380 builder.append(BOLD).append(intentType).append(RESET)
381 .append(" (").append(total).append(')').append('\n');
382 builder.append('\t')
383 .append("installed: ").append(installed).append(' ')
384 .append("withdrawn: ").append(withdrawn).append(' ')
385 .append("failed: ").append(failed)
386 .append('\n');
387 builder.append('\t')
388 .append("compiling: ").append(compiling).append(' ')
389 .append("installing: ").append(installing).append(' ')
390 .append("recompiling: ").append(recompiling).append(' ')
391 .append("withdrawing: ").append(withdrawing)
392 .append('\n');
393 builder.append('\t')
394 .append("installReq: ").append(installReq).append(' ')
395 .append("withdrawReq: ").append(withdrawReq).append(' ')
396 .append("unknownState: ").append(unknownState)
397 .append('\n')
398 .append('\n');
399 return builder;
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800400 }
401
402 /**
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800403 * Gets the JSON representation of the Intent Summary.
404 *
405 * @param mapper the object mapper
406 * @return the JSON representation of the Intent Summary
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800407 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800408 JsonNode json(ObjectMapper mapper) {
409 ObjectNode result = mapper.createObjectNode()
410 .put("total", total)
411 .put("installed", installed)
412 .put("failed", failed)
413 .put("installReq", installReq)
414 .put("installing", installing)
415 .put("compiling", compiling)
416 .put("recompiling", recompiling)
417 .put("withdrawReq", withdrawReq)
418 .put("withdrawing", withdrawing)
419 .put("withdrawn", withdrawn)
420 .put("unknownState", unknownState);
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800421
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800422 return result;
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800423 }
424 }
425
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800426 /**
427 * Merges 2 {@link IntentSummary} together.
428 *
429 * @param a element to merge
430 * @param b element to merge
431 * @return merged {@link IntentSummary}
Luca Prete5db2e872016-12-07 18:31:00 -0800432 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800433 IntentSummary merge(IntentSummary a, IntentSummary b) {
434 IntentSummary m = new IntentSummary(firstNonNull(a.intentType, b.intentType));
435 m.total = a.total + b.total;
436 m.installReq = a.installReq + b.installReq;
437 m.compiling = a.compiling + b.compiling;
438 m.installing = a.installing + b.installing;
439 m.installed = a.installed + b.installed;
440 m.recompiling = a.recompiling + b.recompiling;
441 m.withdrawing = a.withdrawing + b.withdrawing;
442 m.withdrawReq = a.withdrawReq + b.withdrawReq;
443 m.withdrawn = a.withdrawn + b.withdrawn;
444 m.failed = a.failed + b.failed;
445 m.unknownState = a.unknownState + b.unknownState;
446 return m;
447 }
448
449 /**
450 * Returns IntentType string.
451 *
452 * @param intent input
453 * @return IntentType string
454 */
455 private static String intentType(Intent intent) {
456 return intent.getClass().getSimpleName().replace("Intent", "");
457 }
458
459 /**
460 * Build summary of intents per intent type.
461 *
462 * @param intents to summarize
463 * @return summaries per Intent type
464 */
465 private Map<String, IntentSummary> summarize(Iterable<Intent> intents) {
466 Map<String, List<Intent>> perIntent = Tools.stream(intents)
Carolina Fernandez0b1449d2016-12-04 13:30:36 +0100467 .collect(Collectors.groupingBy(IntentsListCommand::intentType));
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800468
469 List<IntentSummary> collect = perIntent.values().stream()
470 .map(il ->
471 il.stream()
472 .map(IntentSummary::new)
473 .reduce(new IntentSummary(), this::merge)
474 ).collect(Collectors.toList());
475
476 Map<String, IntentSummary> summaries = new HashMap<>();
477
478 // individual
479 collect.forEach(is -> summaries.put(is.intentType, is));
480
481 // all summarised
482 summaries.put("All", collect.stream()
483 .reduce(new IntentSummary("All"), this::merge));
484 return summaries;
485 }
486
487 /**
488 * Returns detailed information text about a specific intent.
489 *
490 * @param intent to print
491 * @param state of intent
492 * @return detailed information or "" if {@code state} was null
493 */
494 private StringBuilder detailsFormat(Intent intent, IntentState state) {
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100495 StringBuilder builder = new StringBuilder();
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800496 if (state == null) {
497 return builder;
498 }
Sho SHIMIZUd7d18002015-01-21 14:37:14 -0800499 if (!intent.resources().isEmpty()) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800500 builder.append('\n').append(format(RESOURCES, intent.resources()));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700501 }
502 if (intent instanceof ConnectivityIntent) {
503 ConnectivityIntent ci = (ConnectivityIntent) intent;
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700504 if (!ci.selector().criteria().isEmpty()) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800505 builder.append('\n').append(format(COMMON_SELECTOR, formatSelector(ci.selector())));
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700506 }
Ray Milkey42507352015-03-20 15:16:10 -0700507 if (!ci.treatment().allInstructions().isEmpty()) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800508 builder.append('\n').append(format(TREATMENT, ci.treatment().allInstructions()));
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700509 }
Thomas Vachuskaedc944c2014-11-04 15:42:25 -0800510 if (ci.constraints() != null && !ci.constraints().isEmpty()) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800511 builder.append('\n').append(format(CONSTRAINTS, ci.constraints()));
Thomas Vachuskaedc944c2014-11-04 15:42:25 -0800512 }
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700513 }
514
Pavlin Radoslavovaab51a32014-12-08 11:07:38 -0800515 if (intent instanceof HostToHostIntent) {
516 HostToHostIntent pi = (HostToHostIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800517 builder.append('\n').append(format(SRC + HOST, pi.one()));
518 builder.append('\n').append(format(DST + HOST, pi.two()));
Pavlin Radoslavovaab51a32014-12-08 11:07:38 -0800519 } else if (intent instanceof PointToPointIntent) {
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700520 PointToPointIntent pi = (PointToPointIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800521 builder.append('\n').append(formatFilteredCps(Sets.newHashSet(pi.filteredIngressPoint()), INGRESS));
522 builder.append('\n').append(formatFilteredCps(Sets.newHashSet(pi.filteredEgressPoint()), EGRESS));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700523 } else if (intent instanceof MultiPointToSinglePointIntent) {
524 MultiPointToSinglePointIntent pi = (MultiPointToSinglePointIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800525 builder.append('\n').append(formatFilteredCps(pi.filteredIngressPoints(), INGRESS));
526 builder.append('\n').append(formatFilteredCps(Sets.newHashSet(pi.filteredEgressPoint()), EGRESS));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700527 } else if (intent instanceof SinglePointToMultiPointIntent) {
528 SinglePointToMultiPointIntent pi = (SinglePointToMultiPointIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800529 builder.append('\n').append(formatFilteredCps(Sets.newHashSet(pi.filteredIngressPoint()), INGRESS));
530 builder.append('\n').append(formatFilteredCps(pi.filteredEgressPoints(), EGRESS));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700531 } else if (intent instanceof PathIntent) {
532 PathIntent pi = (PathIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800533 builder.append(format("path=%s, cost=%f", pi.path().links(), pi.path().cost()));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700534 } else if (intent instanceof LinkCollectionIntent) {
535 LinkCollectionIntent li = (LinkCollectionIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800536 builder.append('\n').append(format("links=%s", li.links()));
537 builder.append('\n').append(format(CP, li.egressPoints()));
Rimon Ashkenazyf0699702016-01-17 19:28:49 +0200538 } else if (intent instanceof OpticalCircuitIntent) {
539 OpticalCircuitIntent ci = (OpticalCircuitIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800540 builder.append('\n').append(format("src=%s, dst=%s", ci.getSrc(), ci.getDst()));
Andrea Campanella449e63c2017-04-20 18:25:14 +0200541 builder.append('\n').append(format("signal type=%s", ci.getSignalType()));
542 builder.append('\n').append(format("bidirectional=%s", ci.isBidirectional()));
Rimon Ashkenazyf0699702016-01-17 19:28:49 +0200543 } else if (intent instanceof OpticalConnectivityIntent) {
544 OpticalConnectivityIntent ci = (OpticalConnectivityIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800545 builder.append('\n').append(format("src=%s, dst=%s", ci.getSrc(), ci.getDst()));
Andrea Campanella449e63c2017-04-20 18:25:14 +0200546 builder.append('\n').append(format("signal type=%s", ci.getSignalType()));
547 builder.append('\n').append(format("bidirectional=%s", ci.isBidirectional()));
Marc De Leenheeradfeffd2017-06-22 16:05:34 -0700548 builder.append('\n').append(format("ochSignal=%s", ci.ochSignal()));
Rimon Ashkenazy27438ff2016-03-22 15:57:45 +0200549 } else if (intent instanceof OpticalOduIntent) {
550 OpticalOduIntent ci = (OpticalOduIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800551 builder.append('\n').append(format("src=%s, dst=%s", ci.getSrc(), ci.getDst()));
Andrea Campanella449e63c2017-04-20 18:25:14 +0200552 builder.append('\n').append(format("signal type=%s", ci.getSignalType()));
553 builder.append('\n').append(format("bidirectional=%s", ci.isBidirectional()));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700554 }
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700555
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800556 List<Intent> installable = service.getInstallableIntents(intent.key());
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100557 installable.stream().filter(i -> contentFilter.filter(i));
Brian O'Connorfe0f4b12014-10-30 21:19:02 -0700558 if (showInstallable && installable != null && !installable.isEmpty()) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800559 builder.append('\n').append(format(INSTALLABLE, installable));
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100560 }
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800561 return builder;
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100562 }
563
Luca Prete5db2e872016-12-07 18:31:00 -0800564 /*
565 * Prints out a formatted string, given a list of connect points.
566 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800567 private StringBuilder formatFilteredCps(Set<FilteredConnectPoint> fCps, String prefix) {
Luca Prete5db2e872016-12-07 18:31:00 -0800568 StringBuilder builder = new StringBuilder();
569 builder.append(prefix);
570 builder.append(FILTERED_CPS);
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800571 fCps.forEach(fCp -> builder.append('\n').append(formatFilteredCp(fCp)));
Luca Prete5db2e872016-12-07 18:31:00 -0800572
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800573 return builder;
Luca Prete5db2e872016-12-07 18:31:00 -0800574 }
575
576 /*
577 * Prints out a formatted string, given a filtered connect point.
578 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800579 private StringBuilder formatFilteredCp(FilteredConnectPoint fCp) {
Luca Prete5db2e872016-12-07 18:31:00 -0800580 ConnectPoint connectPoint = fCp.connectPoint();
581 TrafficSelector selector = fCp.trafficSelector();
582 StringBuilder builder = new StringBuilder();
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800583 builder.append(INDENTATION).append(format(CP, connectPoint));
584 builder.append(SPACE).append(format(SELECTOR, formatSelector(selector)));
Luca Prete5db2e872016-12-07 18:31:00 -0800585
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800586 return builder;
Luca Prete5db2e872016-12-07 18:31:00 -0800587 }
588
589 /*
590 * Prints out a formatted string, given a traffic selector
591 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800592 private StringBuilder formatSelector(TrafficSelector ts) {
Luca Prete5db2e872016-12-07 18:31:00 -0800593 StringBuilder builder = new StringBuilder();
594 List<Criterion> criteria = Lists.newArrayList(ts.criteria());
595
596 if (criteria == null || criteria.isEmpty()) {
597 builder.append(INHERITED);
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800598 return builder;
Luca Prete5db2e872016-12-07 18:31:00 -0800599 }
600
601 criteria.forEach(c -> {
602 builder.append(c.toString());
603 if (criteria.indexOf(c) < criteria.size() - 1) {
604 builder.append(", ");
605 }
606 });
607
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800608 return builder;
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100609 }
610
Luca Prete5db2e872016-12-07 18:31:00 -0800611 /*
612 * Prints information about the intent state, given an intent.
613 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800614 private StringBuilder fullFormat(Intent intent, IntentState state) {
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100615 StringBuilder builder = new StringBuilder();
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800616 builder.append(format(ID, intent.id()));
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100617 if (state != null) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800618 builder.append('\n').append(format(STATE, state));
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100619 }
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800620 builder.append('\n').append(format(KEY, intent.key()));
621 builder.append('\n').append(format(TYPE, intent.getClass().getSimpleName()));
622 builder.append('\n').append(format(APP_ID, intent.appId().name()));
Luca Prete5db2e872016-12-07 18:31:00 -0800623
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800624 return builder;
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700625 }
626
Luca Prete5db2e872016-12-07 18:31:00 -0800627 /*
628 * Produces a JSON array from the intents specified.
629 */
630 private JsonNode json(Iterable<Intent> intents) {
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700631 ObjectMapper mapper = new ObjectMapper();
632 ArrayNode result = mapper.createArrayNode();
Carolina Fernandez0b1449d2016-12-04 13:30:36 +0100633 Tools.stream(intents)
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100634 .filter(intent -> contentFilter.filter(jsonForEntity(intent, Intent.class).toString()))
635 .forEach(intent -> result.add(jsonForEntity(intent, Intent.class)));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700636 return result;
637 }
tomf5c9d922014-10-03 15:22:03 -0700638}