blob: cb4839688d0e40a854e2b693d7b038eab3da5abc [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;
Luca Prete5db2e872016-12-07 18:31:00 -080059import java.util.stream.StreamSupport;
tomf5c9d922014-10-03 15:22:03 -070060
61/**
62 * Lists the inventory of intents and their states.
63 */
64@Command(scope = "onos", name = "intents",
65 description = "Lists the inventory of intents and their states")
66public class IntentsListCommand extends AbstractShellCommand {
67
Luca Prete5db2e872016-12-07 18:31:00 -080068 // Color codes and style
69 private static final String BOLD = "\u001B[1m";
70 private static final String RESET = "\u001B[0m";
71
72 // Messages and string formatter
73 private static final String APP_ID = BOLD + "Application Id:" + RESET + " %s";
74
75 private static final String COMMON_SELECTOR = BOLD + "Common ingress " +
76 "selector:" + RESET + " %s";
77
78 private static final String CP = BOLD + "Connect Point:" + RESET + " %s";
79
80 private static final String CONSTRAINTS = BOLD + "Constraints:" + RESET + " %s";
81
82 private static final String DST = BOLD + "Destination " + RESET;
83
84 private static final String EGRESS = BOLD + "Egress ";
85
86 private static final String FILTERED_CPS = "connect points and individual selectors" + RESET;
87
88 private static final String HOST = "host:" + RESET + " %s";
89
90 private static final String ID = BOLD + "Id:" + RESET + " %s";
91
92 private static final String INHERITED = "Inherited";
93
94 private static final String INGRESS = BOLD + "Ingress ";
95
96 private static final String INDENTATION = " -> ";
97
98 private static final String INSTALLABLE = BOLD + "Installable:" + RESET + " %s";
99
100 private static final String KEY = BOLD + "Key:" + RESET + " %s";
101
102 private static final String RESOURCES = BOLD + "Resources:" + RESET + " %s";
103
104 private static final String SELECTOR = BOLD + "Selector:" + RESET + " %s";
105
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800106 private static final String SEPARATOR = StringUtils.repeat("-", 172);
Luca Prete5db2e872016-12-07 18:31:00 -0800107
108 private static final String SPACE = " ";
109
110 private static final String SRC = BOLD + "Source ";
111
112 private static final String STATE = BOLD + "State:" + RESET + " %s";
113
114 private static final String TREATMENT = BOLD + "Treatment:" + RESET + " %s";
115
116 private static final String TYPE = BOLD + "Intent type:" + RESET + " %s";
117
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800118 /**
119 * {@value #SUMMARY_TITLES}.
120 */
Luca Prete5db2e872016-12-07 18:31:00 -0800121 private static final String SUMMARY_TITLES =
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800122 BOLD + format(
Luca Prete5db2e872016-12-07 18:31:00 -0800123 "\n%1s%21s%14s%14s%14s%14s%14s%14s%14s%14s%14s%14s",
124 "Intent type",
125 "Total",
126 "Installed",
127 "Withdrawn",
128 "Failed",
129 "InstallReq",
130 "Compiling",
131 "Installing",
132 "Recompiling",
133 "WithdrawReq",
134 "Withdrawing",
135 "UnknownState") +
136 RESET;
137
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800138 @Option(name = "-i", aliases = "--installable",
139 description = "Output Installable Intents",
Brian O'Connorfe0f4b12014-10-30 21:19:02 -0700140 required = false, multiValued = false)
141 private boolean showInstallable = false;
142
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800143 @Option(name = "-s", aliases = "--summary",
144 description = "Intents summary",
145 required = false, multiValued = false)
146 private boolean intentsSummary = false;
Brian O'Connorfe0f4b12014-10-30 21:19:02 -0700147
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800148 @Option(name = "-m", aliases = "--mini-summary",
149 description = "Intents mini summary",
150 required = false, multiValued = false)
151 private boolean miniSummary = false;
152
Jonathan Hart34f1e382015-02-24 16:52:23 -0800153 @Option(name = "-p", aliases = "--pending",
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100154 description = "Show information about pending intents",
Jonathan Hart34f1e382015-02-24 16:52:23 -0800155 required = false, multiValued = false)
156 private boolean pending = false;
157
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100158 @Option(name = "-f", aliases = "--filter",
Yuta HIGUCHIfadb9a32017-01-13 09:33:10 -0800159 description = "Filter intents by specific keyword",
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100160 required = false, multiValued = true)
161 private List<String> filter = new ArrayList<>();
162
163 private StringFilter contentFilter;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800164 private IntentService service;
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100165
tomf5c9d922014-10-03 15:22:03 -0700166 @Override
167 protected void execute() {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800168 service = get(IntentService.class);
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100169 contentFilter = new StringFilter(filter, StringFilter.Strategy.AND);
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800170
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800171 Iterable<Intent> intents;
172 if (pending) {
173 intents = service.getPending();
174 } else {
175 intents = service.getIntents();
176 }
177
178 if (intentsSummary || miniSummary) {
179 Map<String, IntentSummary> summarized = summarize(intents);
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800180 if (outputJson()) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800181 ObjectNode summaries = mapper().createObjectNode();
182 summarized.forEach((n, s) -> summaries.set(uncapitalize(n), s.json(mapper())));
183 print("%s", summaries);
184 } else if (miniSummary) {
185 StringBuilder builder = new StringBuilder();
186 builder.append(summarized.remove("All").miniSummary());
187 summarized.values().forEach(s -> builder.append(s.miniSummary()));
188 print("%s", builder.toString());
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800189 } else {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800190 StringBuilder builder = new StringBuilder();
191 builder.append(SUMMARY_TITLES);
192 builder.append('\n').append(SEPARATOR);
193 builder.append(summarized.remove("All").summary());
194 summarized.values().forEach(s -> builder.append(s.summary()));
195 print("%s", builder.toString());
Ray Milkey740c8a32015-03-17 13:41:03 -0700196 }
Jonathan Hart34f1e382015-02-24 16:52:23 -0800197 return;
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800198 }
199
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700200 if (outputJson()) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800201 print("%s", json(intents));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700202 } else {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800203 for (Intent intent : intents) {
204 IntentState state = service.getIntentState(intent.key());
205 StringBuilder intentFormat = fullFormat(intent, state);
206 StringBuilder detailsIntentFormat = detailsFormat(intent, state);
207 String formatted = intentFormat.append(detailsIntentFormat).toString();
208 if (contentFilter.filter(formatted)) {
209 print("%s\n", formatted);
210 }
211 }
tomf5c9d922014-10-03 15:22:03 -0700212 }
213 }
214
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800215 /**
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800216 * Internal local class to keep track of a single type Intent summary.
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800217 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800218 private class IntentSummary {
219 private final String intentType;
220 private int total = 0;
221 private int installReq = 0;
222 private int compiling = 0;
223 private int installing = 0;
224 private int installed = 0;
225 private int recompiling = 0;
226 private int withdrawReq = 0;
227 private int withdrawing = 0;
228 private int withdrawn = 0;
229 private int failed = 0;
230 private int unknownState = 0;
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800231
232 /**
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800233 * Creates empty {@link IntentSummary} for specified {@code intentType}.
234 *
235 * @param intentType the string describing the Intent type
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800236 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800237 IntentSummary(String intentType) {
238 this.intentType = intentType;
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800239 }
240
241 /**
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800242 * Creates {@link IntentSummary} initialized with given {@code intent}.
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800243 *
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800244 * @param intent to initialize with
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800245 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800246 IntentSummary(Intent intent) {
247 // remove "Intent" from intentType label
248 this(intentType(intent));
249 update(service.getIntentState(intent.key()));
250 }
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800251
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800252 // for identity element, when reducing
253 IntentSummary() {
254 this.intentType = null;
255 }
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800256
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800257 /**
258 * Updates the Intent Summary.
259 *
260 * @param intentState the state of the intent
261 */
262 void update(IntentState intentState) {
263 total++;
264 switch (intentState) {
265 case INSTALL_REQ:
266 installReq++;
267 break;
268 case COMPILING:
269 compiling++;
270 break;
271 case INSTALLING:
272 installing++;
273 break;
274 case INSTALLED:
275 installed++;
276 break;
277 case RECOMPILING:
278 recompiling++;
279 break;
280 case WITHDRAW_REQ:
281 withdrawReq++;
282 break;
283 case WITHDRAWING:
284 withdrawing++;
285 break;
286 case WITHDRAWN:
287 withdrawn++;
288 break;
289 case FAILED:
290 failed++;
291 break;
292 default:
293 unknownState++;
294 break;
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800295 }
296 }
297
298 /**
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800299 * Prints the Intent Summary.
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800300 *
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800301 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800302 StringBuilder summary() {
Luca Prete5db2e872016-12-07 18:31:00 -0800303 StringBuilder builder = new StringBuilder();
Luca Prete5db2e872016-12-07 18:31:00 -0800304
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800305 builder.append(format(
306 "\n%1s%s%14d%14d%14d%14d%14d%14d%14d%14d%14d%14d",
307 BOLD + intentType + RESET,
308 Strings.padStart(String.valueOf(total),
309 (32 - intentType.length()),
310 ' '),
311 installed,
312 withdrawn,
313 failed,
314 installReq,
315 compiling,
316 installing,
317 recompiling,
318 withdrawReq,
319 withdrawing,
320 unknownState));
321 builder.append('\n').append(SEPARATOR);
322
323 return builder;
324 }
325
326 StringBuilder miniSummary() {
327 StringBuilder builder = new StringBuilder();
328 builder.append(BOLD).append(intentType).append(RESET)
329 .append(" (").append(total).append(')').append('\n');
330 builder.append('\t')
331 .append("installed: ").append(installed).append(' ')
332 .append("withdrawn: ").append(withdrawn).append(' ')
333 .append("failed: ").append(failed)
334 .append('\n');
335 builder.append('\t')
336 .append("compiling: ").append(compiling).append(' ')
337 .append("installing: ").append(installing).append(' ')
338 .append("recompiling: ").append(recompiling).append(' ')
339 .append("withdrawing: ").append(withdrawing)
340 .append('\n');
341 builder.append('\t')
342 .append("installReq: ").append(installReq).append(' ')
343 .append("withdrawReq: ").append(withdrawReq).append(' ')
344 .append("unknownState: ").append(unknownState)
345 .append('\n')
346 .append('\n');
347 return builder;
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800348 }
349
350 /**
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800351 * Gets the JSON representation of the Intent Summary.
352 *
353 * @param mapper the object mapper
354 * @return the JSON representation of the Intent Summary
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800355 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800356 JsonNode json(ObjectMapper mapper) {
357 ObjectNode result = mapper.createObjectNode()
358 .put("total", total)
359 .put("installed", installed)
360 .put("failed", failed)
361 .put("installReq", installReq)
362 .put("installing", installing)
363 .put("compiling", compiling)
364 .put("recompiling", recompiling)
365 .put("withdrawReq", withdrawReq)
366 .put("withdrawing", withdrawing)
367 .put("withdrawn", withdrawn)
368 .put("unknownState", unknownState);
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800369
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800370 return result;
Pavlin Radoslavov708e8202014-11-14 17:18:37 -0800371 }
372 }
373
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800374 /**
375 * Merges 2 {@link IntentSummary} together.
376 *
377 * @param a element to merge
378 * @param b element to merge
379 * @return merged {@link IntentSummary}
Luca Prete5db2e872016-12-07 18:31:00 -0800380 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800381 IntentSummary merge(IntentSummary a, IntentSummary b) {
382 IntentSummary m = new IntentSummary(firstNonNull(a.intentType, b.intentType));
383 m.total = a.total + b.total;
384 m.installReq = a.installReq + b.installReq;
385 m.compiling = a.compiling + b.compiling;
386 m.installing = a.installing + b.installing;
387 m.installed = a.installed + b.installed;
388 m.recompiling = a.recompiling + b.recompiling;
389 m.withdrawing = a.withdrawing + b.withdrawing;
390 m.withdrawReq = a.withdrawReq + b.withdrawReq;
391 m.withdrawn = a.withdrawn + b.withdrawn;
392 m.failed = a.failed + b.failed;
393 m.unknownState = a.unknownState + b.unknownState;
394 return m;
395 }
396
397 /**
398 * Returns IntentType string.
399 *
400 * @param intent input
401 * @return IntentType string
402 */
403 private static String intentType(Intent intent) {
404 return intent.getClass().getSimpleName().replace("Intent", "");
405 }
406
407 /**
408 * Build summary of intents per intent type.
409 *
410 * @param intents to summarize
411 * @return summaries per Intent type
412 */
413 private Map<String, IntentSummary> summarize(Iterable<Intent> intents) {
414 Map<String, List<Intent>> perIntent = Tools.stream(intents)
415 .collect(Collectors.groupingBy(i -> intentType(i)));
416
417 List<IntentSummary> collect = perIntent.values().stream()
418 .map(il ->
419 il.stream()
420 .map(IntentSummary::new)
421 .reduce(new IntentSummary(), this::merge)
422 ).collect(Collectors.toList());
423
424 Map<String, IntentSummary> summaries = new HashMap<>();
425
426 // individual
427 collect.forEach(is -> summaries.put(is.intentType, is));
428
429 // all summarised
430 summaries.put("All", collect.stream()
431 .reduce(new IntentSummary("All"), this::merge));
432 return summaries;
433 }
434
435 /**
436 * Returns detailed information text about a specific intent.
437 *
438 * @param intent to print
439 * @param state of intent
440 * @return detailed information or "" if {@code state} was null
441 */
442 private StringBuilder detailsFormat(Intent intent, IntentState state) {
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100443 StringBuilder builder = new StringBuilder();
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800444 if (state == null) {
445 return builder;
446 }
Sho SHIMIZUd7d18002015-01-21 14:37:14 -0800447 if (!intent.resources().isEmpty()) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800448 builder.append('\n').append(format(RESOURCES, intent.resources()));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700449 }
450 if (intent instanceof ConnectivityIntent) {
451 ConnectivityIntent ci = (ConnectivityIntent) intent;
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700452 if (!ci.selector().criteria().isEmpty()) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800453 builder.append('\n').append(format(COMMON_SELECTOR, formatSelector(ci.selector())));
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700454 }
Ray Milkey42507352015-03-20 15:16:10 -0700455 if (!ci.treatment().allInstructions().isEmpty()) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800456 builder.append('\n').append(format(TREATMENT, ci.treatment().allInstructions()));
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700457 }
Thomas Vachuskaedc944c2014-11-04 15:42:25 -0800458 if (ci.constraints() != null && !ci.constraints().isEmpty()) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800459 builder.append('\n').append(format(CONSTRAINTS, ci.constraints()));
Thomas Vachuskaedc944c2014-11-04 15:42:25 -0800460 }
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700461 }
462
Pavlin Radoslavovaab51a32014-12-08 11:07:38 -0800463 if (intent instanceof HostToHostIntent) {
464 HostToHostIntent pi = (HostToHostIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800465 builder.append('\n').append(format(SRC + HOST, pi.one()));
466 builder.append('\n').append(format(DST + HOST, pi.two()));
Pavlin Radoslavovaab51a32014-12-08 11:07:38 -0800467 } else if (intent instanceof PointToPointIntent) {
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700468 PointToPointIntent pi = (PointToPointIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800469 builder.append('\n').append(formatFilteredCps(Sets.newHashSet(pi.filteredIngressPoint()), INGRESS));
470 builder.append('\n').append(formatFilteredCps(Sets.newHashSet(pi.filteredEgressPoint()), EGRESS));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700471 } else if (intent instanceof MultiPointToSinglePointIntent) {
472 MultiPointToSinglePointIntent pi = (MultiPointToSinglePointIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800473 builder.append('\n').append(formatFilteredCps(pi.filteredIngressPoints(), INGRESS));
474 builder.append('\n').append(formatFilteredCps(Sets.newHashSet(pi.filteredEgressPoint()), EGRESS));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700475 } else if (intent instanceof SinglePointToMultiPointIntent) {
476 SinglePointToMultiPointIntent pi = (SinglePointToMultiPointIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800477 builder.append('\n').append(formatFilteredCps(Sets.newHashSet(pi.filteredIngressPoint()), INGRESS));
478 builder.append('\n').append(formatFilteredCps(pi.filteredEgressPoints(), EGRESS));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700479 } else if (intent instanceof PathIntent) {
480 PathIntent pi = (PathIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800481 builder.append(format("path=%s, cost=%f", pi.path().links(), pi.path().cost()));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700482 } else if (intent instanceof LinkCollectionIntent) {
483 LinkCollectionIntent li = (LinkCollectionIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800484 builder.append('\n').append(format("links=%s", li.links()));
485 builder.append('\n').append(format(CP, li.egressPoints()));
Rimon Ashkenazyf0699702016-01-17 19:28:49 +0200486 } else if (intent instanceof OpticalCircuitIntent) {
487 OpticalCircuitIntent ci = (OpticalCircuitIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800488 builder.append('\n').append(format("src=%s, dst=%s", ci.getSrc(), ci.getDst()));
Rimon Ashkenazyf0699702016-01-17 19:28:49 +0200489 } else if (intent instanceof OpticalConnectivityIntent) {
490 OpticalConnectivityIntent ci = (OpticalConnectivityIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800491 builder.append('\n').append(format("src=%s, dst=%s", ci.getSrc(), ci.getDst()));
Rimon Ashkenazy27438ff2016-03-22 15:57:45 +0200492 } else if (intent instanceof OpticalOduIntent) {
493 OpticalOduIntent ci = (OpticalOduIntent) intent;
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800494 builder.append('\n').append(format("src=%s, dst=%s", ci.getSrc(), ci.getDst()));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700495 }
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700496
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800497 List<Intent> installable = service.getInstallableIntents(intent.key());
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100498 installable.stream().filter(i -> contentFilter.filter(i));
Brian O'Connorfe0f4b12014-10-30 21:19:02 -0700499 if (showInstallable && installable != null && !installable.isEmpty()) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800500 builder.append('\n').append(format(INSTALLABLE, installable));
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100501 }
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800502 return builder;
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100503 }
504
Luca Prete5db2e872016-12-07 18:31:00 -0800505 /*
506 * Prints out a formatted string, given a list of connect points.
507 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800508 private StringBuilder formatFilteredCps(Set<FilteredConnectPoint> fCps, String prefix) {
Luca Prete5db2e872016-12-07 18:31:00 -0800509 StringBuilder builder = new StringBuilder();
510 builder.append(prefix);
511 builder.append(FILTERED_CPS);
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800512 fCps.forEach(fCp -> builder.append('\n').append(formatFilteredCp(fCp)));
Luca Prete5db2e872016-12-07 18:31:00 -0800513
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800514 return builder;
Luca Prete5db2e872016-12-07 18:31:00 -0800515 }
516
517 /*
518 * Prints out a formatted string, given a filtered connect point.
519 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800520 private StringBuilder formatFilteredCp(FilteredConnectPoint fCp) {
Luca Prete5db2e872016-12-07 18:31:00 -0800521 ConnectPoint connectPoint = fCp.connectPoint();
522 TrafficSelector selector = fCp.trafficSelector();
523 StringBuilder builder = new StringBuilder();
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800524 builder.append(INDENTATION).append(format(CP, connectPoint));
525 builder.append(SPACE).append(format(SELECTOR, formatSelector(selector)));
Luca Prete5db2e872016-12-07 18:31:00 -0800526
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800527 return builder;
Luca Prete5db2e872016-12-07 18:31:00 -0800528 }
529
530 /*
531 * Prints out a formatted string, given a traffic selector
532 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800533 private StringBuilder formatSelector(TrafficSelector ts) {
Luca Prete5db2e872016-12-07 18:31:00 -0800534 StringBuilder builder = new StringBuilder();
535 List<Criterion> criteria = Lists.newArrayList(ts.criteria());
536
537 if (criteria == null || criteria.isEmpty()) {
538 builder.append(INHERITED);
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800539 return builder;
Luca Prete5db2e872016-12-07 18:31:00 -0800540 }
541
542 criteria.forEach(c -> {
543 builder.append(c.toString());
544 if (criteria.indexOf(c) < criteria.size() - 1) {
545 builder.append(", ");
546 }
547 });
548
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800549 return builder;
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100550 }
551
Luca Prete5db2e872016-12-07 18:31:00 -0800552 /*
553 * Prints information about the intent state, given an intent.
554 */
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800555 private StringBuilder fullFormat(Intent intent, IntentState state) {
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100556 StringBuilder builder = new StringBuilder();
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800557 builder.append(format(ID, intent.id()));
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100558 if (state != null) {
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800559 builder.append('\n').append(format(STATE, state));
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100560 }
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800561 builder.append('\n').append(format(KEY, intent.key()));
562 builder.append('\n').append(format(TYPE, intent.getClass().getSimpleName()));
563 builder.append('\n').append(format(APP_ID, intent.appId().name()));
Luca Prete5db2e872016-12-07 18:31:00 -0800564
Yuta HIGUCHIf0e09cd2017-01-27 10:52:36 -0800565 return builder;
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700566 }
567
Luca Prete5db2e872016-12-07 18:31:00 -0800568 /*
569 * Produces a JSON array from the intents specified.
570 */
571 private JsonNode json(Iterable<Intent> intents) {
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700572 ObjectMapper mapper = new ObjectMapper();
573 ArrayNode result = mapper.createArrayNode();
Carolina Fernandezfa56d142016-11-14 01:13:26 +0100574 StreamSupport.stream(intents.spliterator(), false)
575 .filter(intent -> contentFilter.filter(jsonForEntity(intent, Intent.class).toString()))
576 .forEach(intent -> result.add(jsonForEntity(intent, Intent.class)));
Thomas Vachuska6ce73042014-10-21 10:01:49 -0700577 return result;
578 }
579
tomf5c9d922014-10-03 15:22:03 -0700580}