Adds loose filtering capability (-f) to cli commands (intents, flows)
- Multi-valued filtering
- Two search strategies (and/or) [defaults to add]
Change-Id: Ia9ad9233b65209b20550ba699c238b88ffb43f8d
diff --git a/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java b/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java
index 659dd96..9de96f9 100644
--- a/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java
@@ -22,6 +22,7 @@
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.apache.karaf.shell.commands.Option;
+import org.onlab.util.StringFilter;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.utils.Comparators;
import org.onosproject.core.ApplicationId;
@@ -34,6 +35,7 @@
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.TrafficTreatment;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -90,13 +92,21 @@
required = false, multiValued = false)
private boolean countOnly = false;
+ @Option(name = "-f", aliases = "--filter",
+ description = "Filter flows by specific key",
+ required = false, multiValued = true)
+ private List<String> filter = new ArrayList<>();
+
private Predicate<FlowEntry> predicate = TRUE_PREDICATE;
+ private StringFilter contentFilter;
+
@Override
protected void execute() {
CoreService coreService = get(CoreService.class);
DeviceService deviceService = get(DeviceService.class);
FlowRuleService service = get(FlowRuleService.class);
+ contentFilter = new StringFilter(filter, StringFilter.Strategy.AND);
compilePredicate();
@@ -211,13 +221,15 @@
*/
protected void printFlows(Device d, List<FlowEntry> flows,
CoreService coreService) {
- boolean empty = flows == null || flows.isEmpty();
- print("deviceId=%s, flowRuleCount=%d", d.id(), empty ? 0 : flows.size());
+ List<FlowEntry> filteredFlows = flows.stream().
+ filter(f -> contentFilter.filter(f)).collect(Collectors.toList());
+ boolean empty = filteredFlows == null || filteredFlows.isEmpty();
+ print("deviceId=%s, flowRuleCount=%d", d.id(), empty ? 0 : filteredFlows.size());
if (empty || countOnly) {
return;
}
- for (FlowEntry f : flows) {
+ for (FlowEntry f : filteredFlows) {
if (shortOutput) {
print(SHORT_FORMAT, f.state(), f.bytes(), f.packets(),
f.tableId(), f.priority(), f.selector().criteria(),
diff --git a/cli/src/main/java/org/onosproject/cli/net/IntentsListCommand.java b/cli/src/main/java/org/onosproject/cli/net/IntentsListCommand.java
index 609c5f9..eb80fad 100644
--- a/cli/src/main/java/org/onosproject/cli/net/IntentsListCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/IntentsListCommand.java
@@ -15,10 +15,13 @@
*/
package org.onosproject.cli.net;
+import java.util.ArrayList;
import java.util.List;
+import java.util.stream.StreamSupport;
import org.apache.karaf.shell.commands.Command;
import org.apache.karaf.shell.commands.Option;
+import org.onlab.util.StringFilter;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.intent.ConnectivityIntent;
import org.onosproject.net.intent.HostToHostIntent;
@@ -57,13 +60,23 @@
private boolean intentsSummary = false;
@Option(name = "-p", aliases = "--pending",
- description = "Show inforamtion about pending intents",
+ description = "Show information about pending intents",
required = false, multiValued = false)
private boolean pending = false;
+ @Option(name = "-f", aliases = "--filter",
+ description = "Filter intents by specific key",
+ required = false, multiValued = true)
+ private List<String> filter = new ArrayList<>();
+
+ private StringFilter contentFilter;
+
+ private String sep = System.lineSeparator();
+
@Override
protected void execute() {
IntentService service = get(IntentService.class);
+ contentFilter = new StringFilter(filter, StringFilter.Strategy.AND);
if (intentsSummary) {
IntentSummaries intentSummaries = new IntentSummaries();
@@ -79,12 +92,9 @@
if (outputJson()) {
print("%s", json(service, service.getPending()));
} else {
- service.getPending().forEach(intent ->
- print("id=%s, key=%s, type=%s, appId=%s",
- intent.id(), intent.key(),
- intent.getClass().getSimpleName(),
- intent.appId().name())
- );
+ StreamSupport.stream(service.getPending().spliterator(), false)
+ .filter(intent -> contentFilter.filter(intent))
+ .forEach(intent -> print(fullFormat(intent)));
}
return;
}
@@ -92,16 +102,7 @@
if (outputJson()) {
print("%s", json(service, service.getIntents()));
} else {
- for (Intent intent : service.getIntents()) {
- IntentState state = service.getIntentState(intent.key());
- if (state != null) {
- print("id=%s, state=%s, key=%s, type=%s, appId=%s",
- intent.id(), state, intent.key(),
- intent.getClass().getSimpleName(),
- intent.appId().name());
- printDetails(service, intent);
- }
- }
+ printIntents(service);
}
}
@@ -158,6 +159,9 @@
if (intentState == null) {
continue;
}
+ if (!contentFilter.filter(intent)) {
+ break;
+ }
// Update the summary for all Intents
summaryAll.update(intentState);
@@ -368,56 +372,89 @@
}
}
- private void printDetails(IntentService service, Intent intent) {
+ private String detailsFormat(IntentService service, Intent intent) {
+ StringBuilder builder = new StringBuilder();
if (!intent.resources().isEmpty()) {
- print(" resources=%s", intent.resources());
+ builder.append(String.format(" resources=%s%s", intent.resources(), sep));
}
if (intent instanceof ConnectivityIntent) {
ConnectivityIntent ci = (ConnectivityIntent) intent;
if (!ci.selector().criteria().isEmpty()) {
- print(" selector=%s", ci.selector().criteria());
+ builder.append(String.format(" selector=%s%s", ci.selector().criteria(), sep));
}
if (!ci.treatment().allInstructions().isEmpty()) {
- print(" treatment=%s", ci.treatment().allInstructions());
+ builder.append(String.format(" treatment=%s%s", ci.treatment().allInstructions(), sep));
}
if (ci.constraints() != null && !ci.constraints().isEmpty()) {
- print(" constraints=%s", ci.constraints());
+ builder.append(String.format(" constraints=%s%s", ci.constraints(), sep));
}
}
if (intent instanceof HostToHostIntent) {
HostToHostIntent pi = (HostToHostIntent) intent;
- print(" host1=%s, host2=%s", pi.one(), pi.two());
+ builder.append(String.format(" host1=%s, host2=%s", pi.one(), pi.two()));
} else if (intent instanceof PointToPointIntent) {
PointToPointIntent pi = (PointToPointIntent) intent;
- print(" ingress=%s, egress=%s", pi.ingressPoint(), pi.egressPoint());
+ builder.append(String.format(" ingress=%s, egress=%s", pi.ingressPoint(), pi.egressPoint()));
} else if (intent instanceof MultiPointToSinglePointIntent) {
MultiPointToSinglePointIntent pi = (MultiPointToSinglePointIntent) intent;
- print(" ingress=%s, egress=%s", pi.ingressPoints(), pi.egressPoint());
+ builder.append(String.format(" ingress=%s, egress=%s", pi.ingressPoints(), pi.egressPoint()));
} else if (intent instanceof SinglePointToMultiPointIntent) {
SinglePointToMultiPointIntent pi = (SinglePointToMultiPointIntent) intent;
- print(" ingress=%s, egress=%s", pi.ingressPoint(), pi.egressPoints());
+ builder.append(String.format(" ingress=%s, egress=%s", pi.ingressPoint(), pi.egressPoints()));
} else if (intent instanceof PathIntent) {
PathIntent pi = (PathIntent) intent;
- print(" path=%s, cost=%d", pi.path().links(), pi.path().cost());
+ builder.append(String.format(" path=%s, cost=%d", pi.path().links(), pi.path().cost()));
} else if (intent instanceof LinkCollectionIntent) {
LinkCollectionIntent li = (LinkCollectionIntent) intent;
- print(" links=%s", li.links());
- print(" egress=%s", li.egressPoints());
+ builder.append(String.format(" links=%s", li.links()));
+ builder.append(String.format(" egress=%s", li.egressPoints()));
} else if (intent instanceof OpticalCircuitIntent) {
OpticalCircuitIntent ci = (OpticalCircuitIntent) intent;
- print(" src=%s, dst=%s", ci.getSrc(), ci.getDst());
+ builder.append(String.format(" src=%s, dst=%s", ci.getSrc(), ci.getDst()));
} else if (intent instanceof OpticalConnectivityIntent) {
OpticalConnectivityIntent ci = (OpticalConnectivityIntent) intent;
- print(" src=%s, dst=%s", ci.getSrc(), ci.getDst());
+ builder.append(String.format(" src=%s, dst=%s", ci.getSrc(), ci.getDst()));
} else if (intent instanceof OpticalOduIntent) {
OpticalOduIntent ci = (OpticalOduIntent) intent;
- print(" src=%s, dst=%s", ci.getSrc(), ci.getDst());
+ builder.append(String.format(" src=%s, dst=%s", ci.getSrc(), ci.getDst()));
}
List<Intent> installable = service.getInstallableIntents(intent.key());
+ installable.stream().filter(i -> contentFilter.filter(i));
if (showInstallable && installable != null && !installable.isEmpty()) {
- print(" installable=%s", installable);
+ builder.append(String.format("%s installable=%s", sep, installable));
+ }
+ return builder.toString();
+ }
+
+ private String fullFormat(Intent intent) {
+ return fullFormat(intent, null);
+ }
+
+ private String fullFormat(Intent intent, String state) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(String.format("id=%s, ", intent.id()));
+ if (state != null) {
+ builder.append(String.format("state=%s, ", state));
+ }
+ builder.append(String.format("key=%s, type=%s, appId=%s",
+ intent.key(),
+ intent.getClass().getSimpleName(),
+ intent.appId().name()));
+ return builder.toString();
+ }
+
+ private void printIntents(IntentService service) {
+ for (Intent intent : service.getIntents()) {
+ IntentState state = service.getIntentState(intent.key());
+ String intentFormat = fullFormat(intent, state.toString());
+ String detailsIntentFormat = detailsFormat(service, intent);
+ if (state != null && (contentFilter.filter(
+ intentFormat + detailsIntentFormat))) {
+ print(intentFormat);
+ print(detailsIntentFormat);
+ }
}
}
@@ -425,8 +462,9 @@
private JsonNode json(IntentService service, Iterable<Intent> intents) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
-
- intents.forEach(intent -> result.add(jsonForEntity(intent, Intent.class)));
+ StreamSupport.stream(intents.spliterator(), false)
+ .filter(intent -> contentFilter.filter(jsonForEntity(intent, Intent.class).toString()))
+ .forEach(intent -> result.add(jsonForEntity(intent, Intent.class)));
return result;
}
diff --git a/utils/misc/src/main/java/org/onlab/util/StringFilter.java b/utils/misc/src/main/java/org/onlab/util/StringFilter.java
new file mode 100644
index 0000000..46037a2
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/util/StringFilter.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onlab.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Filters content on a given object with String representation.
+ * This is carried out through restrictive (AND) or loose (OR) searches.
+ * If not provided, strategy defaults to ADD.
+ */
+public class StringFilter {
+
+ /**
+ * Defines the filtering strategy.
+ */
+ public enum Strategy {
+ AND,
+ OR
+ }
+
+ private Strategy strategy = Strategy.AND;
+ private List<String> filter = new ArrayList<>();
+
+ /**
+ * Creates a new filter to apply on some data.
+ *
+ * @param filter list with filters to apply
+ */
+ public StringFilter(List<String> filter) {
+ this.filter = filter;
+ }
+
+ /**
+ * Creates a new filter to apply on some data,
+ * given a specific strategy (AND, OR).
+ *
+ * @param filter list with filters to apply
+ * @param strategy type of strategy (AND, OR)
+ */
+ public StringFilter(List<String> filter, Strategy strategy) {
+ this(filter);
+ checkArgument(strategy == Strategy.AND || strategy == Strategy.OR,
+ "Chosen strategy is not allowed (should be one of {AND, OR})");
+ this.strategy = strategy;
+ }
+
+ /**
+ * Filters data according to a set of restrictions and the AND strategy.
+ *
+ * @param data Object with data to filter
+ * @return true if data honours the filter, false otherwise
+ */
+ private boolean filterAnd(Object data) {
+ return filter.isEmpty() ||
+ filter.stream().filter(data.toString()::contains)
+ .count() == filter.size();
+ }
+
+ /**
+ * Filters data according to a set of restrictions and the OR strategy.
+ *
+ * @param data Object with data to filter
+ * @return true if data honours the filter, false otherwise
+ */
+ private boolean filterOr(Object data) {
+ return filter.isEmpty() ||
+ filter.stream().filter(data.toString()::contains)
+ .count() > 0;
+ }
+
+ /**
+ * Filters data according to a set of restrictions and a specific strategy.
+ *
+ * @param data Object with data to filter
+ * @return true if data honours the filters, false otherwise
+ */
+ public boolean filter(Object data) {
+ if (strategy == Strategy.OR) {
+ return filterOr(data);
+ } else {
+ return filterAnd(data);
+ }
+ }
+}