diff options
Diffstat (limited to 'framework/src/onos/cli')
125 files changed, 11197 insertions, 0 deletions
diff --git a/framework/src/onos/cli/pom.xml b/framework/src/onos/cli/pom.xml new file mode 100644 index 00000000..a9cd180d --- /dev/null +++ b/framework/src/onos/cli/pom.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright 2014 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. + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onosproject</groupId> + <artifactId>onos</artifactId> + <version>1.3.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>onos-cli</artifactId> + <packaging>bundle</packaging> + + <description>ONOS administrative console command-line extensions + </description> + + <dependencies> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-api</artifactId> + </dependency> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-incubator-api</artifactId> + </dependency> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onlab-osgi</artifactId> + </dependency> + <dependency> + <groupId>org.onosproject</groupId> + <artifactId>onos-core-common</artifactId> + </dependency> + + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-annotations</artifactId> + </dependency> + + <dependency> + <groupId>org.osgi</groupId> + <artifactId>org.osgi.core</artifactId> + </dependency> + <dependency> + <groupId>org.apache.karaf.shell</groupId> + <artifactId>org.apache.karaf.shell.console</artifactId> + </dependency> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.scr.annotations</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + </plugin> + + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-scr-plugin</artifactId> + </plugin> + </plugins> + </build> + +</project> diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/AbstractChoicesCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/AbstractChoicesCompleter.java new file mode 100644 index 00000000..b846fdeb --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/AbstractChoicesCompleter.java @@ -0,0 +1,38 @@ +/* + * Copyright 2015 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.onosproject.cli; + +import org.apache.karaf.shell.console.completer.StringsCompleter; + +import java.util.List; +import java.util.SortedSet; + +/** + * Abstraction of a completer with preset choices. + */ +public abstract class AbstractChoicesCompleter extends AbstractCompleter { + + protected abstract List<String> choices(); + + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + StringsCompleter delegate = new StringsCompleter(); + SortedSet<String> strings = delegate.getStrings(); + choices().forEach(strings::add); + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/AbstractCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/AbstractCompleter.java new file mode 100644 index 00000000..f232596c --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/AbstractCompleter.java @@ -0,0 +1,39 @@ +/* + * Copyright 2015 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.onosproject.cli; + +import org.apache.felix.service.command.CommandSession; +import org.apache.karaf.shell.console.CommandSessionHolder; +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.ArgumentCompleter; + +/** + * Abstract argument completer. + */ +public abstract class AbstractCompleter implements Completer { + + /** + * Returns the argument list. + * + * @return argument list + */ + protected ArgumentCompleter.ArgumentList getArgumentList() { + CommandSession session = CommandSessionHolder.getSession(); + return (ArgumentCompleter.ArgumentList) + session.get(ArgumentCompleter.ARGUMENTS_LIST); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/AbstractShellCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/AbstractShellCommand.java new file mode 100644 index 00000000..8945d62a --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/AbstractShellCommand.java @@ -0,0 +1,167 @@ +/* + * Copyright 2014-2015 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.onosproject.cli; + +import org.apache.karaf.shell.commands.Option; +import org.apache.karaf.shell.console.AbstractAction; +import org.onlab.osgi.DefaultServiceDirectory; +import org.onlab.osgi.ServiceNotFoundException; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.CodecService; +import org.onosproject.codec.JsonCodec; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.Annotations; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Base abstraction of Karaf shell commands. + */ +public abstract class AbstractShellCommand extends AbstractAction implements CodecContext { + + @Option(name = "-j", aliases = "--json", description = "Output JSON", + required = false, multiValued = false) + private boolean json = false; + + /** + * Returns the reference to the implementation of the specified service. + * + * @param serviceClass service class + * @param <T> type of service + * @return service implementation + * @throws org.onlab.osgi.ServiceNotFoundException if service is unavailable + */ + public static <T> T get(Class<T> serviceClass) { + return DefaultServiceDirectory.getService(serviceClass); + } + + /** + * Returns application ID for the CLI. + * + * @return command-line application identifier + */ + protected ApplicationId appId() { + return get(CoreService.class) + .registerApplication("org.onosproject.cli"); + } + + /** + * Prints the arguments using the specified format. + * + * @param format format string; see {@link String#format} + * @param args arguments + */ + public void print(String format, Object... args) { + System.out.println(String.format(format, args)); + } + + /** + * Prints the arguments using the specified format to error stream. + * + * @param format format string; see {@link String#format} + * @param args arguments + */ + public void error(String format, Object... args) { + System.err.println(String.format(format, args)); + } + + /** + * Produces a string image of the specified key/value annotations. + * + * @param annotations key/value annotations + * @return string image with ", k1=v1, k2=v2, ..." pairs + */ + public static String annotations(Annotations annotations) { + StringBuilder sb = new StringBuilder(); + for (String key : annotations.keys()) { + sb.append(", ").append(key).append('=').append(annotations.value(key)); + } + return sb.toString(); + } + + /** + * Produces a JSON object from the specified key/value annotations. + * + * @param mapper ObjectMapper to use while converting to JSON + * @param annotations key/value annotations + * @return JSON object + */ + public static ObjectNode annotations(ObjectMapper mapper, Annotations annotations) { + ObjectNode result = mapper.createObjectNode(); + for (String key : annotations.keys()) { + result.put(key, annotations.value(key)); + } + return result; + } + + /** + * Executes this command. + */ + protected abstract void execute(); + + /** + * Indicates whether JSON format should be output. + * + * @return true if JSON is requested + */ + protected boolean outputJson() { + return json; + } + + @Override + protected Object doExecute() throws Exception { + try { + execute(); + } catch (ServiceNotFoundException e) { + error(e.getMessage()); + } + return null; + } + + + + private final ObjectMapper mapper = new ObjectMapper(); + + @Override + public ObjectMapper mapper() { + return mapper; + } + + @Override + @SuppressWarnings("unchecked") + public <T> JsonCodec<T> codec(Class<T> entityClass) { + return get(CodecService.class).getCodec(entityClass); + } + + @Override + public <T> T getService(Class<T> serviceClass) { + return get(serviceClass); + } + + /** + * Generates a Json representation of an object. + * + * @param entity object to generate JSON for + * @param entityClass class to format with - this chooses which codec to use + * @param <T> Type of the object being formatted + * @return JSON object representation + */ + public <T> ObjectNode jsonForEntity(T entity, Class<T> entityClass) { + return codec(entityClass).encode(entity, this); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/BalanceMastersCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/BalanceMastersCommand.java new file mode 100644 index 00000000..9a35ce34 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/BalanceMastersCommand.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 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.onosproject.cli; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.mastership.MastershipAdminService; + +/** + * Forces device mastership rebalancing. + */ +@Command(scope = "onos", name = "balance-masters", + description = "Forces device mastership rebalancing") +public class BalanceMastersCommand extends AbstractShellCommand { + + @Override + protected void execute() { + get(MastershipAdminService.class).balanceRoles(); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/CliComponent.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/CliComponent.java new file mode 100644 index 00000000..6ae816bd --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/CliComponent.java @@ -0,0 +1,39 @@ +/* + * Copyright 2015 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.onosproject.cli; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onosproject.core.CoreService; + +/** + * OSGI Component for the ONOS CLI. + */ + +@Component(immediate = true) +public class CliComponent { + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Activate + public void activate() { + coreService + .registerApplication("org.onosproject.cli"); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/Comparators.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/Comparators.java new file mode 100644 index 00000000..0ab6845f --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/Comparators.java @@ -0,0 +1,126 @@ +/* + * Copyright 2014-2015 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.onosproject.cli; + +import org.onosproject.cluster.ControllerNode; +import org.onosproject.core.Application; +import org.onosproject.core.ApplicationId; +import org.onosproject.incubator.net.intf.Interface; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Element; +import org.onosproject.net.ElementId; +import org.onosproject.net.Port; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.group.Group; +import org.onosproject.net.host.PortAddresses; +import org.onosproject.net.topology.TopologyCluster; + +import java.util.Comparator; + +/** + * Various comparators. + */ +public final class Comparators { + + // Ban construction + private Comparators() { + } + + public static final Comparator<ApplicationId> APP_ID_COMPARATOR = new Comparator<ApplicationId>() { + @Override + public int compare(ApplicationId id1, ApplicationId id2) { + return id1.id() - id2.id(); + } + }; + + public static final Comparator<Application> APP_COMPARATOR = new Comparator<Application>() { + @Override + public int compare(Application app1, Application app2) { + return app1.id().id() - app2.id().id(); + } + }; + + public static final Comparator<ElementId> ELEMENT_ID_COMPARATOR = new Comparator<ElementId>() { + @Override + public int compare(ElementId id1, ElementId id2) { + return id1.toString().compareTo(id2.toString()); + } + }; + + public static final Comparator<Element> ELEMENT_COMPARATOR = new Comparator<Element>() { + @Override + public int compare(Element e1, Element e2) { + return e1.id().toString().compareTo(e2.id().toString()); + } + }; + + public static final Comparator<FlowRule> FLOW_RULE_COMPARATOR = new Comparator<FlowRule>() { + @Override + public int compare(FlowRule f1, FlowRule f2) { + return Long.valueOf(f1.id().value()).compareTo(f2.id().value()); + } + }; + + public static final Comparator<Group> GROUP_COMPARATOR = new Comparator<Group>() { + @Override + public int compare(Group g1, Group g2) { + return Long.valueOf(g1.id().id()).compareTo(Long.valueOf(g2.id().id())); + } + }; + + public static final Comparator<Port> PORT_COMPARATOR = new Comparator<Port>() { + @Override + public int compare(Port p1, Port p2) { + long delta = p1.number().toLong() - p2.number().toLong(); + return delta == 0 ? 0 : (delta < 0 ? -1 : +1); + } + }; + + public static final Comparator<TopologyCluster> CLUSTER_COMPARATOR = new Comparator<TopologyCluster>() { + @Override + public int compare(TopologyCluster c1, TopologyCluster c2) { + return c1.id().index() - c2.id().index(); + } + }; + + public static final Comparator<ControllerNode> NODE_COMPARATOR = new Comparator<ControllerNode>() { + @Override + public int compare(ControllerNode ci1, ControllerNode ci2) { + return ci1.id().toString().compareTo(ci2.id().toString()); + } + }; + + public static final Comparator<ConnectPoint> CONNECT_POINT_COMPARATOR = new Comparator<ConnectPoint>() { + @Override + public int compare(ConnectPoint o1, ConnectPoint o2) { + int compareId = ELEMENT_ID_COMPARATOR.compare(o1.elementId(), o2.elementId()); + return (compareId != 0) ? + compareId : + Long.signum(o1.port().toLong() - o2.port().toLong()); + } + }; + + public static final Comparator<PortAddresses> ADDRESSES_COMPARATOR = new Comparator<PortAddresses>() { + @Override + public int compare(PortAddresses arg0, PortAddresses arg1) { + return CONNECT_POINT_COMPARATOR.compare(arg0.connectPoint(), arg1.connectPoint()); + } + }; + + public static final Comparator<Interface> INTERFACES_COMPARATOR = (intf1, intf2) -> + CONNECT_POINT_COMPARATOR.compare(intf1.connectPoint(), intf2.connectPoint()); + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/MastersListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/MastersListCommand.java new file mode 100644 index 00000000..8675a3c8 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/MastersListCommand.java @@ -0,0 +1,92 @@ +/* + * Copyright 2014 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.onosproject.cli; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.google.common.collect.Lists; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cluster.ClusterService; +import org.onosproject.cluster.ControllerNode; +import org.onosproject.mastership.MastershipService; +import org.onosproject.net.DeviceId; + +import java.util.Collections; +import java.util.List; + +import static com.google.common.collect.Lists.newArrayList; + +/** + * Lists device mastership information. + */ +@Command(scope = "onos", name = "masters", + description = "Lists device mastership information") +public class MastersListCommand extends AbstractShellCommand { + + @Override + protected void execute() { + ClusterService service = get(ClusterService.class); + MastershipService mastershipService = get(MastershipService.class); + List<ControllerNode> nodes = newArrayList(service.getNodes()); + Collections.sort(nodes, Comparators.NODE_COMPARATOR); + + if (outputJson()) { + print("%s", json(service, mastershipService, nodes)); + } else { + for (ControllerNode node : nodes) { + List<DeviceId> ids = Lists.newArrayList(mastershipService.getDevicesOf(node.id())); + Collections.sort(ids, Comparators.ELEMENT_ID_COMPARATOR); + print("%s: %d devices", node.id(), ids.size()); + for (DeviceId deviceId : ids) { + print(" %s", deviceId); + } + } + } + } + + // Produces JSON structure. + private JsonNode json(ClusterService service, MastershipService mastershipService, + List<ControllerNode> nodes) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode result = mapper.createArrayNode(); + ControllerNode self = service.getLocalNode(); + for (ControllerNode node : nodes) { + List<DeviceId> ids = Lists.newArrayList(mastershipService.getDevicesOf(node.id())); + result.add(mapper.createObjectNode() + .put("id", node.id().toString()) + .put("size", ids.size()) + .set("devices", json(mapper, ids))); + } + return result; + } + + /** + * Produces a JSON array containing the specified device identifiers. + * + * @param mapper object mapper + * @param ids collection of device identifiers + * @return JSON array + */ + public static JsonNode json(ObjectMapper mapper, Iterable<DeviceId> ids) { + ArrayNode result = mapper.createArrayNode(); + for (DeviceId deviceId : ids) { + result.add(deviceId.toString()); + } + return result; + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/MetricNameCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/MetricNameCompleter.java new file mode 100644 index 00000000..f05181f5 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/MetricNameCompleter.java @@ -0,0 +1,34 @@ +/* + * Copyright 2015 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.onosproject.cli; + +import org.onlab.metrics.MetricsService; + +import java.util.ArrayList; +import java.util.List; + +/** + * Metric name completer. + */ +public class MetricNameCompleter extends AbstractChoicesCompleter { + + @Override + protected List<String> choices() { + MetricsService metricsService = AbstractShellCommand.get(MetricsService.class); + return new ArrayList<String>(metricsService.getMetrics().keySet()); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/MetricsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/MetricsListCommand.java new file mode 100644 index 00000000..9b80485b --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/MetricsListCommand.java @@ -0,0 +1,167 @@ +/* + * Copyright 2014 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.onosproject.cli; + +import com.codahale.metrics.Counter; +import com.codahale.metrics.Gauge; +import com.codahale.metrics.Histogram; +import com.codahale.metrics.Meter; +import com.codahale.metrics.Metric; +import com.codahale.metrics.MetricFilter; +import com.codahale.metrics.Snapshot; +import com.codahale.metrics.Timer; +import com.google.common.base.Strings; +import com.google.common.collect.Ordering; +import com.google.common.collect.TreeMultimap; +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.joda.time.LocalDateTime; +import org.onlab.metrics.MetricsService; + +import java.util.Comparator; +import java.util.Map; +import java.util.Map.Entry; + +import static java.lang.String.format; + +/** + * Prints metrics in the system. + */ +@Command(scope = "onos", name = "metrics", + description = "Prints metrics in the system") +public class MetricsListCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "metricName", description = "Name of Metric", + required = false, multiValued = false) + String metricName = null; + + @Override + protected void execute() { + MetricsService metricsService = get(MetricsService.class); + + MetricFilter filter = metricName != null ? (name, metric) -> name.equals(metricName) : MetricFilter.ALL; + + TreeMultimap<String, Metric> matched = listMetrics(metricsService, filter); + matched.asMap().forEach((name, metrics) -> { + for (Metric metric : metrics) { + printMetric(name, metric); + } + }); + } + + /** + * Print metric object. + * + * @param name metric name + * @param metric metric object + */ + private void printMetric(String name, Metric metric) { + final String heading; + + if (metric instanceof Counter) { + heading = format("-- %s : [%s] --", name, "Counter"); + print(heading); + Counter counter = (Counter) metric; + print(" count = %d", counter.getCount()); + + } else if (metric instanceof Gauge) { + heading = format("-- %s : [%s] --", name, "Gauge"); + print(heading); + @SuppressWarnings("rawtypes") + Gauge gauge = (Gauge) metric; + final Object value = gauge.getValue(); + if (name.endsWith("EpochMs") && value instanceof Long) { + print(" value = %s (%s)", value, new LocalDateTime(value)); + } else { + print(" value = %s", value); + } + + } else if (metric instanceof Histogram) { + heading = format("-- %s : [%s] --", name, "Histogram"); + print(heading); + final Histogram histogram = (Histogram) metric; + final Snapshot snapshot = histogram.getSnapshot(); + print(" count = %d", histogram.getCount()); + print(" min = %d", snapshot.getMin()); + print(" max = %d", snapshot.getMax()); + print(" mean = %f", snapshot.getMean()); + print(" stddev = %f", snapshot.getStdDev()); + + } else if (metric instanceof Meter) { + heading = format("-- %s : [%s] --", name, "Meter"); + print(heading); + final Meter meter = (Meter) metric; + print(" count = %d", meter.getCount()); + print(" mean rate = %f", meter.getMeanRate()); + print(" 1-minute rate = %f", meter.getOneMinuteRate()); + print(" 5-minute rate = %f", meter.getFiveMinuteRate()); + print(" 15-minute rate = %f", meter.getFifteenMinuteRate()); + + } else if (metric instanceof Timer) { + heading = format("-- %s : [%s] --", name, "Timer"); + print(heading); + final Timer timer = (Timer) metric; + final Snapshot snapshot = timer.getSnapshot(); + print(" count = %d", timer.getCount()); + print(" mean rate = %f per second", timer.getMeanRate()); + print(" 1-minute rate = %f per second", timer.getOneMinuteRate()); + print(" 5-minute rate = %f per second", timer.getFiveMinuteRate()); + print(" 15-minute rate = %f per second", timer.getFifteenMinuteRate()); + print(" min = %f ms", nanoToMs(snapshot.getMin())); + print(" max = %f ms", nanoToMs(snapshot.getMax())); + print(" mean = %f ms", nanoToMs(snapshot.getMean())); + print(" stddev = %f ms", nanoToMs(snapshot.getStdDev())); + } else { + heading = format("-- %s : [%s] --", name, metric.getClass().getCanonicalName()); + print(heading); + print("Unknown Metric type:{}", metric.getClass().getCanonicalName()); + } + print(Strings.repeat("-", heading.length())); + } + + @SuppressWarnings("rawtypes") + private TreeMultimap<String, Metric> listMetrics(MetricsService metricsService, MetricFilter filter) { + TreeMultimap<String, Metric> metrics = TreeMultimap.create(Comparator.naturalOrder(), Ordering.arbitrary()); + + Map<String, Counter> counters = metricsService.getCounters(filter); + for (Entry<String, Counter> entry : counters.entrySet()) { + metrics.put(entry.getKey(), entry.getValue()); + } + Map<String, Gauge> gauges = metricsService.getGauges(filter); + for (Entry<String, Gauge> entry : gauges.entrySet()) { + metrics.put(entry.getKey(), entry.getValue()); + } + Map<String, Histogram> histograms = metricsService.getHistograms(filter); + for (Entry<String, Histogram> entry : histograms.entrySet()) { + metrics.put(entry.getKey(), entry.getValue()); + } + Map<String, Meter> meters = metricsService.getMeters(filter); + for (Entry<String, Meter> entry : meters.entrySet()) { + metrics.put(entry.getKey(), entry.getValue()); + } + Map<String, Timer> timers = metricsService.getTimers(filter); + for (Entry<String, Timer> entry : timers.entrySet()) { + metrics.put(entry.getKey(), entry.getValue()); + } + + return metrics; + } + + private double nanoToMs(double nano) { + return nano / 1_000_000D; + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/NodeAddCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/NodeAddCommand.java new file mode 100644 index 00000000..37f59918 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/NodeAddCommand.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014-2015 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.onosproject.cli; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cluster.ClusterAdminService; +import org.onosproject.cluster.DefaultControllerNode; +import org.onosproject.cluster.NodeId; +import org.onlab.packet.IpAddress; + +/** + * Adds a new controller cluster node. + */ +@Command(scope = "onos", name = "add-node", + description = "Adds a new controller cluster node") +public class NodeAddCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "nodeId", description = "Node ID", + required = true, multiValued = false) + String nodeId = null; + + @Argument(index = 1, name = "ip", description = "Node IP address", + required = true, multiValued = false) + String ip = null; + + @Argument(index = 2, name = "tcpPort", description = "Node TCP listen port", + required = false, multiValued = false) + int tcpPort = DefaultControllerNode.DEFAULT_PORT; + + @Override + protected void execute() { + ClusterAdminService service = get(ClusterAdminService.class); + service.addNode(new NodeId(nodeId), IpAddress.valueOf(ip), tcpPort); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/NodeIdCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/NodeIdCompleter.java new file mode 100644 index 00000000..8e6db7f4 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/NodeIdCompleter.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014 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.onosproject.cli; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.cluster.ClusterService; +import org.onosproject.cluster.ControllerNode; + +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; + +/** + * Node ID completer. + */ +public class NodeIdCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + + // Fetch our service and feed it's offerings to the string completer + ClusterService service = AbstractShellCommand.get(ClusterService.class); + Iterator<ControllerNode> it = service.getNodes().iterator(); + SortedSet<String> strings = delegate.getStrings(); + while (it.hasNext()) { + strings.add(it.next().id().toString()); + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/NodeRemoveCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/NodeRemoveCommand.java new file mode 100644 index 00000000..c2dbb546 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/NodeRemoveCommand.java @@ -0,0 +1,40 @@ +/* + * Copyright 2014 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.onosproject.cli; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cluster.ClusterAdminService; +import org.onosproject.cluster.NodeId; + +/** + * Removes a controller cluster node. + */ +@Command(scope = "onos", name = "remove-node", + description = "Removes a new controller cluster node") +public class NodeRemoveCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "nodeId", description = "Node ID", + required = true, multiValued = false) + String nodeId = null; + + @Override + protected void execute() { + ClusterAdminService service = get(ClusterAdminService.class); + service.removeNode(new NodeId(nodeId)); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/NodesListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/NodesListCommand.java new file mode 100644 index 00000000..50e8d534 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/NodesListCommand.java @@ -0,0 +1,88 @@ +/* + * Copyright 2014-2015 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.onosproject.cli; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.karaf.shell.commands.Command; +import org.joda.time.DateTime; +import org.onlab.util.Tools; +import org.onosproject.cluster.ClusterService; +import org.onosproject.cluster.ControllerNode; + +import java.util.Collections; +import java.util.List; + +import static com.google.common.collect.Lists.newArrayList; + + +/** + * Lists all controller cluster nodes. + */ +@Command(scope = "onos", name = "nodes", + description = "Lists all controller cluster nodes") +public class NodesListCommand extends AbstractShellCommand { + + private static final String FMT = + "id=%s, address=%s:%s, state=%s, updated=%s %s"; + + @Override + protected void execute() { + ClusterService service = get(ClusterService.class); + List<ControllerNode> nodes = newArrayList(service.getNodes()); + Collections.sort(nodes, Comparators.NODE_COMPARATOR); + if (outputJson()) { + print("%s", json(service, nodes)); + } else { + ControllerNode self = service.getLocalNode(); + for (ControllerNode node : nodes) { + DateTime lastUpdated = service.getLastUpdated(node.id()); + String timeAgo = "Never"; + if (lastUpdated != null) { + timeAgo = Tools.timeAgo(lastUpdated.getMillis()); + } + print(FMT, node.id(), node.ip(), node.tcpPort(), + service.getState(node.id()), + timeAgo, + node.equals(self) ? "*" : ""); + } + } + } + + // Produces JSON structure. + private JsonNode json(ClusterService service, List<ControllerNode> nodes) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode result = mapper.createArrayNode(); + ControllerNode self = service.getLocalNode(); + for (ControllerNode node : nodes) { + ControllerNode.State nodeState = service.getState(node.id()); + ObjectNode newNode = mapper.createObjectNode() + .put("id", node.id().toString()) + .put("ip", node.ip().toString()) + .put("tcpPort", node.tcpPort()) + .put("self", node.equals(self)); + + if (nodeState != null) { + newNode.put("state", nodeState.toString()); + } + result.add(newNode); + } + return result; + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/PlaceholderCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/PlaceholderCompleter.java new file mode 100644 index 00000000..dbd2a971 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/PlaceholderCompleter.java @@ -0,0 +1,40 @@ +/* + * Copyright 2015 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.onosproject.cli; + +import org.apache.karaf.shell.console.completer.StringsCompleter; + +import java.util.List; +import java.util.SortedSet; + +/** + * A completer that can be used as a placeholder for arguments that don't + * need/want completers. + */ +public class PlaceholderCompleter extends AbstractCompleter { + + @Override + public int complete(String s, int i, List<String> list) { + // Populate a string completer with what the user has typed so far + StringsCompleter delegate = new StringsCompleter(); + SortedSet<String> strings = delegate.getStrings(); + if (s != null) { + strings.add(s); + } + return delegate.complete(s, i, list); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/RolesCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/RolesCommand.java new file mode 100644 index 00000000..bc1e9102 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/RolesCommand.java @@ -0,0 +1,101 @@ +/* + * Copyright 2014 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.onosproject.cli; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cluster.NodeId; +import org.onosproject.cluster.RoleInfo; +import org.onosproject.mastership.MastershipService; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.device.DeviceService; + +import java.util.List; + +import static org.onosproject.cli.net.DevicesListCommand.getSortedDevices; + +/** + * Lists mastership roles of nodes for each device. + */ +@Command(scope = "onos", name = "roles", + description = "Lists mastership roles of nodes for each device.") +public class RolesCommand extends AbstractShellCommand { + + private static final String FMT_HDR = "%s: master=%s, standbys=[ %s]"; + + @Override + protected void execute() { + DeviceService deviceService = get(DeviceService.class); + MastershipService roleService = get(MastershipService.class); + + if (outputJson()) { + print("%s", json(roleService, getSortedDevices(deviceService))); + } else { + for (Device d : getSortedDevices(deviceService)) { + DeviceId did = d.id(); + printRoles(roleService, did); + } + } + } + + // Produces JSON structure with role information for the given devices. + private JsonNode json(MastershipService service, List<Device> sortedDevices) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode results = mapper.createArrayNode(); + for (Device device : sortedDevices) { + results.add(json(service, mapper, device)); + } + return results; + } + + // Produces JSON structure with role information for the given device. + private JsonNode json(MastershipService service, ObjectMapper mapper, + Device device) { + NodeId master = service.getMasterFor(device.id()); + ObjectNode result = mapper.createObjectNode() + .put("id", device.id().toString()) + .put("master", master != null ? master.toString() : "none"); + RoleInfo nodes = service.getNodesFor(device.id()); + ArrayNode standbys = mapper.createArrayNode(); + for (NodeId nid : nodes.backups()) { + standbys.add(nid.toString()); + } + result.set("standbys", standbys); + return result; + } + + /** + * Prints the role information for a device. + * + * @param service mastership service + * @param deviceId the ID of the device + */ + protected void printRoles(MastershipService service, DeviceId deviceId) { + RoleInfo nodes = service.getNodesFor(deviceId); + StringBuilder builder = new StringBuilder(); + for (NodeId nid : nodes.backups()) { + builder.append(nid).append(" "); + } + + print(FMT_HDR, deviceId, + nodes.master() == null ? "NONE" : nodes.master(), + builder.toString()); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/StartStopCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/StartStopCompleter.java new file mode 100644 index 00000000..b9d9b0f8 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/StartStopCompleter.java @@ -0,0 +1,34 @@ +/* + * Copyright 2015 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.onosproject.cli; + +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * Start/stop command completer. + */ +public class StartStopCompleter extends AbstractChoicesCompleter { + + public static final String START = "start"; + public static final String STOP = "stop"; + + @Override + public List<String> choices() { + return ImmutableList.of(START, STOP); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/SummaryCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/SummaryCommand.java new file mode 100644 index 00000000..65f4cf97 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/SummaryCommand.java @@ -0,0 +1,89 @@ +/* + * Copyright 2014-2015 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.onosproject.cli; + +import java.util.Set; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cluster.ControllerNode; +import org.onosproject.core.CoreService; +import org.onosproject.cluster.ClusterService; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.flow.FlowRuleService; +import org.onosproject.net.host.HostService; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.link.LinkService; +import org.onosproject.net.topology.Topology; +import org.onosproject.net.topology.TopologyService; + +/** + * Provides summary of ONOS model. + */ +@Command(scope = "onos", name = "summary", + description = "Provides summary of ONOS model") +public class SummaryCommand extends AbstractShellCommand { + + /** + * Count the active ONOS controller nodes. + * + * @param nodes set of all of the controller nodes in the cluster + * @return count of active nodes + */ + private int activeNodes(Set<ControllerNode> nodes) { + int nodeCount = 0; + + for (final ControllerNode node : nodes) { + final ControllerNode.State nodeState = + get(ClusterService.class).getState(node.id()); + if (nodeState == ControllerNode.State.ACTIVE) { + nodeCount++; + } + } + return nodeCount; + } + + @Override + protected void execute() { + TopologyService topologyService = get(TopologyService.class); + Topology topology = topologyService.currentTopology(); + if (outputJson()) { + print("%s", new ObjectMapper().createObjectNode() + .put("node", get(ClusterService.class).getLocalNode().ip().toString()) + .put("version", get(CoreService.class).version().toString()) + .put("nodes", get(ClusterService.class).getNodes().size()) + .put("devices", topology.deviceCount()) + .put("links", topology.linkCount()) + .put("hosts", get(HostService.class).getHostCount()) + .put("SCC(s)", topology.clusterCount()) + .put("flows", get(FlowRuleService.class).getFlowRuleCount()) + .put("intents", get(IntentService.class).getIntentCount())); + } else { + print("node=%s, version=%s", + get(ClusterService.class).getLocalNode().ip(), + get(CoreService.class).version().toString()); + print("nodes=%d, devices=%d, links=%d, hosts=%d, SCC(s)=%s, flows=%d, intents=%d", + activeNodes(get(ClusterService.class).getNodes()), + get(DeviceService.class).getDeviceCount(), + get(LinkService.class).getLinkCount(), + get(HostService.class).getHostCount(), + topologyService.getClusters(topology).size(), + get(FlowRuleService.class).getFlowRuleCount(), + get(IntentService.class).getIntentCount()); + } + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/UiViewListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/UiViewListCommand.java new file mode 100644 index 00000000..33a85e68 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/UiViewListCommand.java @@ -0,0 +1,60 @@ +/* + * Copyright 2015 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.onosproject.cli; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.ui.UiExtension; +import org.onosproject.ui.UiExtensionService; + +import java.util.List; + +/** + * Lists all UI views. + */ +@Command(scope = "onos", name = "ui-views", + description = "Lists all UI views") +public class UiViewListCommand extends AbstractShellCommand { + + private static final String FMT = "id=%s, category=%s, label=%s, icon=%s"; + + @Override + protected void execute() { + UiExtensionService service = get(UiExtensionService.class); + if (outputJson()) { + print("%s", json(service.getExtensions())); + } else { + service.getExtensions().forEach(ext -> ext.views() + .forEach(v -> print(FMT, v.id(), v.category().label(), + v.label(), v.iconId()))); + } + } + + private JsonNode json(List<UiExtension> extensions) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode node = mapper.createArrayNode(); + extensions.forEach(ext -> ext.views() + .forEach(v -> node.add(mapper.createObjectNode() + .put("id", v.id()) + .put("category", v.category().label()) + .put("label", v.label()) + .put("icon", v.iconId())))); + return node; + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/UpDownCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/UpDownCompleter.java new file mode 100644 index 00000000..9d8eda5c --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/UpDownCompleter.java @@ -0,0 +1,34 @@ +/* + * Copyright 2015 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.onosproject.cli; + +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * Up/down command completer. + */ +public class UpDownCompleter extends AbstractChoicesCompleter { + + public static final String UP = "up"; + public static final String DOWN = "down"; + + @Override + public List<String> choices() { + return ImmutableList.of(UP, DOWN); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/AllApplicationNamesCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/AllApplicationNamesCompleter.java new file mode 100644 index 00000000..9006369b --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/AllApplicationNamesCompleter.java @@ -0,0 +1,54 @@ +/* + * Copyright 2015 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.onosproject.cli.app; + +import java.util.Iterator; +import java.util.List; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.StreamSupport; + +import org.onosproject.app.ApplicationService; +import org.onosproject.cli.AbstractChoicesCompleter; +import org.onosproject.core.Application; + +import static java.util.stream.Collectors.toList; +import static org.onosproject.app.ApplicationState.INSTALLED; +import static org.onosproject.cli.AbstractShellCommand.get; + +/** + * All installed application name completer. + */ +public class AllApplicationNamesCompleter extends AbstractChoicesCompleter { + @Override + public List<String> choices() { + + // Fetch the service and return the list of app names + ApplicationService service = get(ApplicationService.class); + Iterator<Application> it = service.getApplications().iterator(); + + // Filter the list of apps, selecting only the installed ones. + // Add each app name to the list of choices. + return + StreamSupport.stream( + Spliterators.spliteratorUnknownSize(it, Spliterator.ORDERED), false) + .filter(app -> service.getState(app.id()) == INSTALLED) + .map(app -> app.id().name()) + .collect(toList()); + + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationCommand.java new file mode 100644 index 00000000..9d40c660 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationCommand.java @@ -0,0 +1,103 @@ +/* + * Copyright 2015 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.onosproject.cli.app; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.app.ApplicationAdminService; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.core.ApplicationId; + +import java.io.IOException; +import java.net.URL; + +/** + * Manages application inventory. + */ +@Command(scope = "onos", name = "app", + description = "Manages application inventory") +public class ApplicationCommand extends AbstractShellCommand { + + static final String INSTALL = "install"; + static final String UNINSTALL = "uninstall"; + static final String ACTIVATE = "activate"; + static final String DEACTIVATE = "deactivate"; + + @Argument(index = 0, name = "command", + description = "Command name (install|activate|deactivate|uninstall)", + required = true, multiValued = false) + String command = null; + + @Argument(index = 1, name = "names", description = "Application name(s) or URL(s)", + required = true, multiValued = true) + String[] names = null; + + @Override + protected void execute() { + ApplicationAdminService service = get(ApplicationAdminService.class); + if (command.equals(INSTALL)) { + for (String name : names) { + if (!installApp(service, name)) { + return; + } + } + + } else { + for (String name : names) { + if (!manageApp(service, name)) { + return; + } + } + } + } + + // Installs the application from input of the specified URL + private boolean installApp(ApplicationAdminService service, String url) { + try { + if (url.equals("-")) { + service.install(System.in); + } else { + service.install(new URL(url).openStream()); + } + } catch (IOException e) { + error("Unable to get URL: %s", url); + return false; + } + return true; + } + + // Manages the specified application. + private boolean manageApp(ApplicationAdminService service, String name) { + ApplicationId appId = service.getId(name); + if (appId == null) { + print("No such application: %s", name); + return false; + } + + if (command.equals(UNINSTALL)) { + service.uninstall(appId); + } else if (command.equals(ACTIVATE)) { + service.activate(appId); + } else if (command.equals(DEACTIVATE)) { + service.deactivate(appId); + } else { + print("Unsupported command: %s", command); + return false; + } + return true; + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationCommandCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationCommandCompleter.java new file mode 100644 index 00000000..51611ff5 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationCommandCompleter.java @@ -0,0 +1,34 @@ +/* + * Copyright 2015 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.onosproject.cli.app; + +import com.google.common.collect.ImmutableList; +import org.onosproject.cli.AbstractChoicesCompleter; + +import java.util.List; + +import static org.onosproject.cli.app.ApplicationCommand.*; + +/** + * Application command completer. + */ +public class ApplicationCommandCompleter extends AbstractChoicesCompleter { + @Override + public List<String> choices() { + return ImmutableList.of(INSTALL, UNINSTALL, ACTIVATE, DEACTIVATE); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationIdListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationIdListCommand.java new file mode 100644 index 00000000..3088a94c --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationIdListCommand.java @@ -0,0 +1,66 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.app; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cli.Comparators; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; + +import java.util.Collections; +import java.util.List; + +import static com.google.common.collect.Lists.newArrayList; + +/** + * Lists application ID information. + */ +@Command(scope = "onos", name = "app-ids", + description = "Lists application ID information") +public class ApplicationIdListCommand extends AbstractShellCommand { + + @Override + protected void execute() { + CoreService service = get(CoreService.class); + List<ApplicationId> ids = newArrayList(service.getAppIds()); + Collections.sort(ids, Comparators.APP_ID_COMPARATOR); + + if (outputJson()) { + print("%s", json(ids)); + } else { + for (ApplicationId id : ids) { + print("id=%d, name=%s", id.id(), id.name()); + } + } + } + + // ApplicationId + private JsonNode json(List<ApplicationId> ids) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode result = mapper.createArrayNode(); + for (ApplicationId id : ids) { + result.add(mapper.createObjectNode() + .put("id", id.id()) + .put("name", id.name())); + } + return result; + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationIdWithIntentNameCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationIdWithIntentNameCompleter.java new file mode 100644 index 00000000..2539ca72 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationIdWithIntentNameCompleter.java @@ -0,0 +1,47 @@ +/* + * Copyright 2015 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.onosproject.cli.app; + +import java.util.List; +import java.util.SortedSet; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.intent.IntentService; + +/** + * Application name completer. + */ +public class ApplicationIdWithIntentNameCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + + // Fetch our service and feed it's offerings to the string completer + IntentService service = AbstractShellCommand.get(IntentService.class); + SortedSet<String> strings = delegate.getStrings(); + + service.getIntents() + .forEach(intent -> + strings.add(intent.appId().name())); + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationNameCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationNameCompleter.java new file mode 100644 index 00000000..17461696 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationNameCompleter.java @@ -0,0 +1,77 @@ +/* + * Copyright 2015 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.onosproject.cli.app; + +import org.apache.karaf.shell.console.completer.ArgumentCompleter; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.app.ApplicationService; +import org.onosproject.app.ApplicationState; +import org.onosproject.cli.AbstractCompleter; +import org.onosproject.core.Application; + +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; + +import static org.onosproject.app.ApplicationState.ACTIVE; +import static org.onosproject.app.ApplicationState.INSTALLED; +import static org.onosproject.cli.AbstractShellCommand.get; + +/** + * Application name completer. + */ +public class ApplicationNameCompleter extends AbstractCompleter { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + + // Command name is the second argument. + ArgumentCompleter.ArgumentList list = getArgumentList(); + String cmd = list.getArguments()[1]; + + // Grab apps already on the command (to prevent tab-completed duplicates) + // FIXME: This does not work. +// final Set previousApps; +// if (list.getArguments().length > 2) { +// previousApps = Sets.newHashSet( +// Arrays.copyOfRange(list.getArguments(), 2, list.getArguments().length)); +// } else { +// previousApps = Collections.emptySet(); +// } + + // Fetch our service and feed it's offerings to the string completer + ApplicationService service = get(ApplicationService.class); + Iterator<Application> it = service.getApplications().iterator(); + SortedSet<String> strings = delegate.getStrings(); + while (it.hasNext()) { + Application app = it.next(); + ApplicationState state = service.getState(app.id()); +// if (previousApps.contains(app.id().name())) { +// continue; +// } + if (cmd.equals("uninstall") || + (cmd.equals("activate") && state == INSTALLED) || + (cmd.equals("deactivate") && state == ACTIVE)) { + strings.add(app.id().name()); + } + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationsListCommand.java new file mode 100644 index 00000000..17cf89e2 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/ApplicationsListCommand.java @@ -0,0 +1,100 @@ +/* + * Copyright 2015 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.onosproject.cli.app; + +import java.util.Collections; +import java.util.List; + +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onosproject.app.ApplicationService; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cli.Comparators; +import org.onosproject.core.Application; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; + +import static com.google.common.collect.Lists.newArrayList; +import static org.onosproject.app.ApplicationState.ACTIVE; + +/** + * Lists application information. + */ +@Command(scope = "onos", name = "apps", + description = "Lists application information") +public class ApplicationsListCommand extends AbstractShellCommand { + + private static final String FMT = + "%s id=%d, name=%s, version=%s, origin=%s, description=%s, " + + "features=%s, featuresRepo=%s, permissions=%s"; + + private static final String SHORT_FMT = + "%s %3d %-32s %-8s %s"; + + @Option(name = "-s", aliases = "--short", description = "Show short output only", + required = false, multiValued = false) + private boolean shortOnly = false; + + @Option(name = "-a", aliases = "--active", description = "Show active only", + required = false, multiValued = false) + private boolean activeOnly = false; + + + @Override + protected void execute() { + ApplicationService service = get(ApplicationService.class); + List<Application> apps = newArrayList(service.getApplications()); + Collections.sort(apps, Comparators.APP_COMPARATOR); + + if (outputJson()) { + print("%s", json(service, apps)); + } else { + for (Application app : apps) { + boolean isActive = service.getState(app.id()) == ACTIVE; + if (activeOnly && isActive || !activeOnly) { + if (shortOnly) { + print(SHORT_FMT, isActive ? "*" : " ", + app.id().id(), app.id().name(), app.version(), + app.description()); + } else { + print(FMT, isActive ? "*" : " ", + app.id().id(), app.id().name(), app.version(), app.origin(), + app.description(), app.features(), + app.featuresRepo().isPresent() ? app.featuresRepo().get().toString() : "", + app.permissions()); + } + } + } + } + } + + private JsonNode json(ApplicationService service, List<Application> apps) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode result = mapper.createArrayNode(); + for (Application app : apps) { + boolean isActive = service.getState(app.id()) == ACTIVE; + if (activeOnly && isActive || !activeOnly) { + result.add(jsonForEntity(app, Application.class)); + } + } + return result; + } + + + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/package-info.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/package-info.java new file mode 100644 index 00000000..37b67fa9 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/app/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015 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. + */ + +/** + * CLI commands for managing distributed inventory of applications. + */ +package org.onosproject.cli.app;
\ No newline at end of file diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/ComponentConfigCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/ComponentConfigCommand.java new file mode 100644 index 00000000..5b9a7283 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/ComponentConfigCommand.java @@ -0,0 +1,182 @@ +/* + * Copyright 2015 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.onosproject.cli.cfg; + +import java.util.Optional; +import java.util.Set; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onosproject.cfg.ComponentConfigService; +import org.onosproject.cfg.ConfigProperty; +import org.onosproject.cli.AbstractShellCommand; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Strings.isNullOrEmpty; + +/** + * Manages component configuration. + */ +@Command(scope = "onos", name = "cfg", + description = "Manages component configuration") +public class ComponentConfigCommand extends AbstractShellCommand { + + static final String GET = "get"; + static final String SET = "set"; + + private static final String FMT = " name=%s, type=%s, value=%s, defaultValue=%s, description=%s"; + private static final String SHORT_FMT = " %s=%s"; + + @Option(name = "-s", aliases = "--short", description = "Show short output only", + required = false, multiValued = false) + private boolean shortOnly = false; + + + @Argument(index = 0, name = "command", + description = "Command name (get|set)", + required = false, multiValued = false) + String command = null; + + @Argument(index = 1, name = "component", description = "Component name", + required = false, multiValued = false) + String component = null; + + @Argument(index = 2, name = "name", description = "Property name", + required = false, multiValued = false) + String name = null; + + @Argument(index = 3, name = "value", description = "Property value", + required = false, multiValued = false) + String value = null; + + ComponentConfigService service; + + @Override + protected void execute() { + service = get(ComponentConfigService.class); + if (isNullOrEmpty(command)) { + listComponents(); + } else if (command.equals(GET) && isNullOrEmpty(component)) { + listAllComponentsProperties(); + } else if (command.equals(GET) && isNullOrEmpty(name)) { + listComponentProperties(component); + } else if (command.equals(GET)) { + listComponentProperty(component, name); + } else if (command.equals(SET) && isNullOrEmpty(value)) { + service.unsetProperty(component, name); + } else if (command.equals(SET)) { + service.setProperty(component, name, value); + } else { + error("Illegal usage"); + } + } + + private void listAllComponentsProperties() { + if (outputJson()) { + print("%s", jsonComponentProperties()); + } else { + service.getComponentNames().forEach(this::listComponentProperties); + } + } + + private JsonNode jsonProperty(ConfigProperty configProperty, ObjectMapper mapper) { + return mapper.createObjectNode() + .put("name", configProperty.name()) + .put("type", configProperty.type().toString().toLowerCase()) + .put("value", configProperty.value()) + .put("defaultValue", configProperty.defaultValue()) + .put("description", configProperty.description()); + } + + private JsonNode jsonComponent(String component, ObjectMapper mapper) { + ObjectNode node = mapper.createObjectNode() + .put("componentName", component); + final ArrayNode propertiesJson = node.putArray("properties"); + Set<ConfigProperty> properties = service.getProperties(component); + if (properties != null) { + properties.forEach(configProperty -> propertiesJson.add( + jsonProperty(configProperty, mapper))); + } + return node; + } + + private JsonNode jsonComponentProperties() { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode result = mapper.createArrayNode(); + service.getComponentNames() + .forEach(component -> result.add(jsonComponent(component, mapper))); + + return result; + } + + private void listComponents() { + if (outputJson()) { + ArrayNode node = new ObjectMapper().createArrayNode(); + service.getComponentNames().forEach(node::add); + print("%s", node); + } else { + service.getComponentNames().forEach(n -> print("%s", n)); + } + } + + private void listComponentProperties(String component) { + if (outputJson()) { + print("%s", jsonComponent(component, new ObjectMapper())); + } else { + Set<ConfigProperty> props = service.getProperties(component); + print("%s", component); + if (props == null) { + print("No properties for component " + component + " found"); + } else if (shortOnly) { + props.forEach(p -> print(SHORT_FMT, p.name(), p.value())); + } else { + props.forEach(p -> print(FMT, p.name(), p.type().toString().toLowerCase(), + p.value(), p.defaultValue(), p.description())); + } + } + } + + private void listComponentProperty(String component, String name) { + Set<ConfigProperty> props = service.getProperties(component); + + if (props == null) { + return; + } + Optional<ConfigProperty> property = props.stream() + .filter(p -> p.name().equals(name)).findFirst(); + if (outputJson()) { + print("%s", jsonProperty(property.get(), new ObjectMapper())); + } else { + if (!property.isPresent()) { + print("Property " + name + " for component " + component + " not found"); + return; + } + ConfigProperty p = property.get(); + if (shortOnly) { + print(SHORT_FMT, p.name(), p.value()); + } else { + print(FMT, p.name(), p.type().toString().toLowerCase(), p.value(), + p.defaultValue(), p.description()); + } + } + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/ComponentConfigCommandCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/ComponentConfigCommandCompleter.java new file mode 100644 index 00000000..5506d816 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/ComponentConfigCommandCompleter.java @@ -0,0 +1,43 @@ +/* + * Copyright 2015 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.onosproject.cli.cfg; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; + +import java.util.List; +import java.util.SortedSet; + +import static org.onosproject.cli.cfg.ComponentConfigCommand.GET; +import static org.onosproject.cli.cfg.ComponentConfigCommand.SET; + +/** + * Component configuration command completer. + */ +public class ComponentConfigCommandCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + SortedSet<String> strings = delegate.getStrings(); + strings.add(GET); + strings.add(SET); + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/ComponentNameCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/ComponentNameCompleter.java new file mode 100644 index 00000000..4883b991 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/ComponentNameCompleter.java @@ -0,0 +1,44 @@ +/* + * Copyright 2015 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.onosproject.cli.cfg; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.cfg.ComponentConfigService; +import org.onosproject.cli.AbstractShellCommand; + +import java.util.List; +import java.util.SortedSet; + +/** + * Component name completer. + */ +public class ComponentNameCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + + // Fetch our service and feed it's offerings to the string completer + ComponentConfigService service = AbstractShellCommand.get(ComponentConfigService.class); + SortedSet<String> strings = delegate.getStrings(); + service.getComponentNames().forEach(strings::add); + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/ComponentPropertyNameCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/ComponentPropertyNameCompleter.java new file mode 100644 index 00000000..98e19690 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/ComponentPropertyNameCompleter.java @@ -0,0 +1,55 @@ +/* + * Copyright 2015 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.onosproject.cli.cfg; + +import org.apache.karaf.shell.console.completer.ArgumentCompleter; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.cfg.ComponentConfigService; +import org.onosproject.cfg.ConfigProperty; +import org.onosproject.cli.AbstractCompleter; + +import java.util.List; +import java.util.Set; +import java.util.SortedSet; + +import static org.onosproject.cli.AbstractShellCommand.get; + +/** + * Component property name completer. + */ +public class ComponentPropertyNameCompleter extends AbstractCompleter { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + + // Component name is the previous argument. + ArgumentCompleter.ArgumentList list = getArgumentList(); + String componentName = list.getArguments()[list.getCursorArgumentIndex() - 1]; + ComponentConfigService service = get(ComponentConfigService.class); + + SortedSet<String> strings = delegate.getStrings(); + Set<ConfigProperty> properties = + service.getProperties(componentName); + if (properties != null) { + properties.forEach(property -> strings.add(property.name())); + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java new file mode 100644 index 00000000..5f2f86ee --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigCommand.java @@ -0,0 +1,107 @@ +/* + * Copyright 2015 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.onosproject.cli.cfg; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.config.Config; +import org.onosproject.net.config.NetworkConfigService; +import org.onosproject.net.config.SubjectFactory; + +import static com.google.common.base.Strings.isNullOrEmpty; + +/** + * Manages network configuration. + */ +@Command(scope = "onos", name = "netcfg", + description = "Manages network configuration") +public class NetworkConfigCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "subjectKey", description = "Subject key", + required = false, multiValued = false) + String subjectKey = null; + + @Argument(index = 1, name = "subject", description = "Subject", + required = false, multiValued = false) + String subject = null; + + @Argument(index = 2, name = "configKey", description = "Config key", + required = false, multiValued = false) + String configKey = null; + + private final ObjectMapper mapper = new ObjectMapper(); + private NetworkConfigService service; + + @Override + protected void execute() { + service = get(NetworkConfigService.class); + JsonNode root = new ObjectMapper().createObjectNode(); + if (isNullOrEmpty(subjectKey)) { + addAll((ObjectNode) root); + } else { + SubjectFactory subjectFactory = service.getSubjectFactory(subjectKey); + if (isNullOrEmpty(subject)) { + addSubjectClass((ObjectNode) root, subjectFactory); + } else { + Object s = subjectFactory.createSubject(subject); + if (isNullOrEmpty(configKey)) { + addSubject((ObjectNode) root, s); + } else { + root = getSubjectConfig(getConfig(s, subjectKey, configKey)); + } + } + } + print("%s", root.toString()); + } + + @SuppressWarnings("unchecked") + private void addAll(ObjectNode root) { + service.getSubjectClasses() + .forEach(sc -> { + SubjectFactory sf = service.getSubjectFactory((Class) sc); + addSubjectClass(newObject(root, sf.subjectKey()), sf); + }); + } + + @SuppressWarnings("unchecked") + private void addSubjectClass(ObjectNode root, SubjectFactory sf) { + service.getSubjects(sf.subjectClass()) + .forEach(s -> addSubject(newObject(root, s.toString()), s)); + } + + private void addSubject(ObjectNode root, Object s) { + service.getConfigs(s).forEach(c -> root.set(c.key(), c.node())); + } + + private JsonNode getSubjectConfig(Config config) { + return config != null ? config.node() : null; + } + + private Config getConfig(Object s, String subjectKey, String ck) { + Class<? extends Config> configClass = service.getConfigClass(subjectKey, ck); + return configClass != null ? service.getConfig(s, configClass) : null; + } + + private ObjectNode newObject(ObjectNode parent, String key) { + ObjectNode node = mapper.createObjectNode(); + parent.set(key, node); + return node; + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigRegistryCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigRegistryCommand.java new file mode 100644 index 00000000..f94967e1 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/NetworkConfigRegistryCommand.java @@ -0,0 +1,51 @@ +/* + * Copyright 2015 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.onosproject.cli.cfg; + +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.config.ConfigFactory; +import org.onosproject.net.config.NetworkConfigRegistry; + +/** + * Displays network configuration registry contents. + */ +@Command(scope = "onos", name = "netcfg-registry", + description = "Displays network configuration registry contents") +public class NetworkConfigRegistryCommand extends AbstractShellCommand { + + private static final String FMT = "subjectKey=%s, configKey=%s, subjectClass=%s, configClass=%s"; + private static final String SHORT_FMT = "%-12s %-12s %-40s %s"; + + @Option(name = "-s", aliases = "--short", description = "Show short output only", + required = false, multiValued = false) + private boolean shortOnly = false; + + @Override + protected void execute() { + get(NetworkConfigRegistry.class).getConfigFactories().forEach(this::print); + } + + private void print(ConfigFactory configFactory) { + print(shortOnly ? SHORT_FMT : FMT, + configFactory.subjectFactory().subjectKey(), + configFactory.configKey(), + configFactory.subjectFactory().subjectClass().getName(), + configFactory.configClass().getName()); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/package-info.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/package-info.java new file mode 100644 index 00000000..0891ddb5 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/cfg/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015 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. + */ + +/** + * CLI commands for managing centralized component and network configurations. + */ +package org.onosproject.cli.cfg;
\ No newline at end of file diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddHostToHostIntentCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddHostToHostIntentCommand.java new file mode 100644 index 00000000..cabf0b3a --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddHostToHostIntentCommand.java @@ -0,0 +1,69 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import java.util.List; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.net.HostId; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.HostToHostIntent; +import org.onosproject.net.intent.IntentService; + +/** + * Installs host-to-host connectivity intent. + */ +@Command(scope = "onos", name = "add-host-intent", + description = "Installs host-to-host connectivity intent") +public class AddHostToHostIntentCommand extends ConnectivityIntentCommand { + + @Argument(index = 0, name = "one", description = "One host ID", + required = true, multiValued = false) + String one = null; + + @Argument(index = 1, name = "two", description = "Another host ID", + required = true, multiValued = false) + String two = null; + + @Override + protected void execute() { + IntentService service = get(IntentService.class); + + HostId oneId = HostId.hostId(one); + HostId twoId = HostId.hostId(two); + + TrafficSelector selector = buildTrafficSelector(); + TrafficTreatment treatment = buildTrafficTreatment(); + List<Constraint> constraints = buildConstraints(); + + HostToHostIntent intent = HostToHostIntent.builder() + .appId(appId()) + .key(key()) + .one(oneId) + .two(twoId) + .selector(selector) + .treatment(treatment) + .constraints(constraints) + .priority(priority()) + .build(); + service.submit(intent); + print("Host to Host intent submitted:\n%s", intent.toString()); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddMeter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddMeter.java new file mode 100644 index 00000000..5a431cd4 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddMeter.java @@ -0,0 +1,68 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.core.CoreService; +import org.onosproject.net.DeviceId; +import org.onosproject.net.meter.Band; +import org.onosproject.net.meter.DefaultBand; +import org.onosproject.net.meter.DefaultMeterRequest; +import org.onosproject.net.meter.Meter; +import org.onosproject.net.meter.MeterRequest; +import org.onosproject.net.meter.MeterService; + +import java.util.Collections; + +/** + * Add a meter. + */ +@Command(scope = "onos", name = "add-meter", + description = "Adds a meter to a device (currently for testing)") +public class AddMeter extends AbstractShellCommand { + + @Argument(index = 0, name = "uri", description = "Device ID", + required = true, multiValued = false) + String uri = null; + + private final String appId = "org.onosproject.cli.meterCmd"; + + @Override + protected void execute() { + MeterService service = get(MeterService.class); + CoreService coreService = get(CoreService.class); + + DeviceId deviceId = DeviceId.deviceId(uri); + + Band band = DefaultBand.builder() + .ofType(Band.Type.DROP) + .withRate(500) + .build(); + + + MeterRequest request = DefaultMeterRequest.builder() + .forDevice(deviceId) + .fromApp(coreService.registerApplication(appId)) + .withUnit(Meter.Unit.KB_PER_SEC) + .withBands(Collections.singleton(band)) + .add(); + + service.submit(request); + + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddMplsIntent.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddMplsIntent.java new file mode 100644 index 00000000..1929b726 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddMplsIntent.java @@ -0,0 +1,91 @@ +package org.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onlab.packet.MplsLabel; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.MplsIntent; + +import java.util.List; +import java.util.Optional; + +/** + * Installs MPLS intents. + */ +@Command(scope = "onos", name = "add-mpls-intent", description = "Installs mpls connectivity intent") +public class AddMplsIntent extends ConnectivityIntentCommand { + + @Argument(index = 0, name = "ingressDevice", + description = "Ingress Device/Port Description", + required = true, + multiValued = false) + private String ingressDeviceString = null; + + @Option(name = "--ingressLabel", + description = "Ingress Mpls label", + required = false, + multiValued = false) + private String ingressLabelString = ""; + + @Argument(index = 1, name = "egressDevice", + description = "Egress Device/Port Description", + required = true, + multiValued = false) + private String egressDeviceString = null; + + @Option(name = "--egressLabel", + description = "Egress Mpls label", + required = false, + multiValued = false) + private String egressLabelString = ""; + + @Override + protected void execute() { + IntentService service = get(IntentService.class); + + ConnectPoint ingress = ConnectPoint.deviceConnectPoint(ingressDeviceString); + Optional<MplsLabel> ingressLabel = Optional.empty(); + if (!ingressLabelString.isEmpty()) { + ingressLabel = Optional + .ofNullable(MplsLabel.mplsLabel(parseInt(ingressLabelString))); + } + + ConnectPoint egress = ConnectPoint.deviceConnectPoint(egressDeviceString); + Optional<MplsLabel> egressLabel = Optional.empty(); + if (!egressLabelString.isEmpty()) { + egressLabel = Optional + .ofNullable(MplsLabel.mplsLabel(parseInt(egressLabelString))); + } + + TrafficSelector selector = buildTrafficSelector(); + TrafficTreatment treatment = buildTrafficTreatment(); + + List<Constraint> constraints = buildConstraints(); + + MplsIntent intent = MplsIntent.builder() + .appId(appId()) + .selector(selector) + .treatment(treatment) + .ingressPoint(ingress) + .ingressLabel(ingressLabel) + .egressPoint(egress) + .egressLabel(egressLabel) + .constraints(constraints) + .priority(priority()) + .build(); + service.submit(intent); + } + + protected Integer parseInt(String value) { + try { + return Integer.parseInt(value); + } catch (NumberFormatException nfe) { + return null; + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddMultiPointToSinglePointIntentCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddMultiPointToSinglePointIntentCommand.java new file mode 100644 index 00000000..dc792f49 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddMultiPointToSinglePointIntentCommand.java @@ -0,0 +1,79 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.MultiPointToSinglePointIntent; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Installs connectivity intent between multiple ingress devices and a single egress device. + */ +@Command(scope = "onos", name = "add-multi-to-single-intent", + description = "Installs connectivity intent between multiple ingress devices and a single egress device") +public class AddMultiPointToSinglePointIntentCommand extends ConnectivityIntentCommand { + + @Argument(index = 0, name = "ingressDevices egressDevice", + description = "ingressDevice/Port..ingressDevice/Port egressDevice/Port", + required = true, multiValued = true) + String[] deviceStrings = null; + + @Override + protected void execute() { + IntentService service = get(IntentService.class); + + if (deviceStrings.length < 2) { + return; + } + + String egressDeviceString = deviceStrings[deviceStrings.length - 1]; + ConnectPoint egress = ConnectPoint.deviceConnectPoint(egressDeviceString); + + Set<ConnectPoint> ingressPoints = new HashSet<>(); + for (int index = 0; index < deviceStrings.length - 1; index++) { + String ingressDeviceString = deviceStrings[index]; + ConnectPoint ingress = ConnectPoint.deviceConnectPoint(ingressDeviceString); + ingressPoints.add(ingress); + } + + TrafficSelector selector = buildTrafficSelector(); + TrafficTreatment treatment = buildTrafficTreatment(); + List<Constraint> constraints = buildConstraints(); + + Intent intent = MultiPointToSinglePointIntent.builder() + .appId(appId()) + .key(key()) + .selector(selector) + .treatment(treatment) + .ingressPoints(ingressPoints) + .egressPoint(egress) + .constraints(constraints) + .priority(priority()) + .build(); + service.submit(intent); + print("Multipoint to single point intent submitted:\n%s", intent.toString()); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java new file mode 100644 index 00000000..57c41009 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddOpticalIntentCommand.java @@ -0,0 +1,125 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.OchPort; +import org.onosproject.net.OduCltPort; +import org.onosproject.net.DeviceId; +import org.onosproject.net.OduSignalType; +import org.onosproject.net.Port; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.OpticalCircuitIntent; +import org.onosproject.net.intent.OpticalConnectivityIntent; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Installs optical connectivity or circuit intents, depending on given port types. + */ +@Command(scope = "onos", name = "add-optical-intent", + description = "Installs optical connectivity intent") +public class AddOpticalIntentCommand extends ConnectivityIntentCommand { + + @Argument(index = 0, name = "ingressDevice", + description = "Ingress Device/Port Description", + required = true, multiValued = false) + String ingressDeviceString = null; + + @Argument(index = 1, name = "egressDevice", + description = "Egress Device/Port Description", + required = true, multiValued = false) + String egressDeviceString = null; + + @Option(name = "-b", aliases = "--bidirectional", + description = "If this argument is passed the optical link created will be bidirectional, " + + "else the link will be unidirectional.", + required = false, multiValued = false) + private boolean bidirectional = false; + + + private ConnectPoint createConnectPoint(String devicePortString) { + String[] splitted = devicePortString.split("/"); + + checkArgument(splitted.length == 2, + "Connect point must be in \"deviceUri/portNumber\" format"); + + DeviceId deviceId = DeviceId.deviceId(splitted[0]); + + DeviceService deviceService = get(DeviceService.class); + + List<Port> ports = deviceService.getPorts(deviceId); + + for (Port port : ports) { + if (splitted[1].equals(port.number().name())) { + return new ConnectPoint(deviceId, port.number()); + } + } + + return null; + } + + @Override + protected void execute() { + IntentService service = get(IntentService.class); + + ConnectPoint ingress = createConnectPoint(ingressDeviceString); + ConnectPoint egress = createConnectPoint(egressDeviceString); + + if (ingress == null || egress == null) { + print("Could not create optical intent"); + } + + DeviceService deviceService = get(DeviceService.class); + Port srcPort = deviceService.getPort(ingress.deviceId(), ingress.port()); + Port dstPort = deviceService.getPort(egress.deviceId(), egress.port()); + + Intent intent; + // FIXME: Hardcoded signal types + if (srcPort instanceof OduCltPort && dstPort instanceof OduCltPort) { + intent = OpticalCircuitIntent.builder() + .appId(appId()) + .key(key()) + .src(ingress) + .dst(egress) + .signalType(OduCltPort.SignalType.CLT_10GBE) + .bidirectional(bidirectional) + .build(); + } else if (srcPort instanceof OchPort && dstPort instanceof OchPort) { + intent = OpticalConnectivityIntent.builder() + .appId(appId()) + .key(key()) + .src(ingress) + .dst(egress) + .signalType(OduSignalType.ODU4) + .bidirectional(bidirectional) + .build(); + } else { + print("Unable to create optical intent between connect points {} and {}", ingress, egress); + return; + } + + service.submit(intent); + print("Optical intent submitted:\n%s", intent.toString()); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddPointToPointIntentCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddPointToPointIntentCommand.java new file mode 100644 index 00000000..7c27dd3d --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddPointToPointIntentCommand.java @@ -0,0 +1,73 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.PointToPointIntent; + +import java.util.List; + +/** + * Installs point-to-point connectivity intents. + */ +@Command(scope = "onos", name = "add-point-intent", + description = "Installs point-to-point connectivity intent") +public class AddPointToPointIntentCommand extends ConnectivityIntentCommand { + + @Argument(index = 0, name = "ingressDevice", + description = "Ingress Device/Port Description", + required = true, multiValued = false) + String ingressDeviceString = null; + + @Argument(index = 1, name = "egressDevice", + description = "Egress Device/Port Description", + required = true, multiValued = false) + String egressDeviceString = null; + + @Override + protected void execute() { + IntentService service = get(IntentService.class); + + ConnectPoint ingress = ConnectPoint.deviceConnectPoint(ingressDeviceString); + + ConnectPoint egress = ConnectPoint.deviceConnectPoint(egressDeviceString); + + TrafficSelector selector = buildTrafficSelector(); + TrafficTreatment treatment = buildTrafficTreatment(); + + List<Constraint> constraints = buildConstraints(); + + Intent intent = PointToPointIntent.builder() + .appId(appId()) + .key(key()) + .selector(selector) + .treatment(treatment) + .ingressPoint(ingress) + .egressPoint(egress) + .constraints(constraints) + .priority(priority()) + .build(); + service.submit(intent); + print("Point to point intent submitted:\n%s", intent.toString()); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddSinglePointToMultiPointIntentCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddSinglePointToMultiPointIntentCommand.java new file mode 100644 index 00000000..2939afae --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddSinglePointToMultiPointIntentCommand.java @@ -0,0 +1,80 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.SinglePointToMultiPointIntent; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Installs connectivity intent between a single ingress device and multiple egress devices. + */ +@Command(scope = "onos", name = "add-single-to-multi-intent", + description = "Installs connectivity intent between a single ingress device and multiple egress devices") +public class AddSinglePointToMultiPointIntentCommand extends ConnectivityIntentCommand { + @Argument(index = 0, name = "ingressDevice egressDevices", + description = "ingressDevice/Port egressDevice/Port...egressDevice/Port", + required = true, multiValued = true) + String[] deviceStrings = null; + + @Override + protected void execute() { + IntentService service = get(IntentService.class); + + if (deviceStrings.length < 2) { + return; + } + + String ingressDeviceString = deviceStrings[0]; + ConnectPoint ingressPoint = ConnectPoint.deviceConnectPoint(ingressDeviceString); + + Set<ConnectPoint> egressPoints = new HashSet<>(); + for (int index = 1; index < deviceStrings.length; index++) { + String egressDeviceString = deviceStrings[index]; + ConnectPoint egress = ConnectPoint.deviceConnectPoint(egressDeviceString); + egressPoints.add(egress); + } + + TrafficSelector selector = buildTrafficSelector(); + TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); + List<Constraint> constraints = buildConstraints(); + + SinglePointToMultiPointIntent intent = + SinglePointToMultiPointIntent.builder() + .appId(appId()) + .key(key()) + .selector(selector) + .treatment(treatment) + .ingressPoint(ingressPoint) + .egressPoints(egressPoints) + .constraints(constraints) + .priority(priority()) + .build(); + service.submit(intent); + print("Single point to multipoint intent submitted:\n%s", intent.toString()); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddTestFlowsCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddTestFlowsCommand.java new file mode 100644 index 00000000..e1e158ab --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddTestFlowsCommand.java @@ -0,0 +1,170 @@ + +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.base.Stopwatch; +import com.google.common.collect.Lists; +import org.apache.commons.lang.math.RandomUtils; +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onlab.packet.MacAddress; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.Device; +import org.onosproject.net.PortNumber; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.flow.DefaultFlowRule; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.FlowRuleOperations; +import org.onosproject.net.flow.FlowRuleOperationsContext; +import org.onosproject.net.flow.FlowRuleService; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * Installs bulk flows. + */ +@Command(scope = "onos", name = "add-test-flows", + description = "Installs a number of test flow rules - for testing only") +public class AddTestFlowsCommand extends AbstractShellCommand { + + private CountDownLatch latch; + + @Argument(index = 0, name = "flowPerDevice", description = "Number of flows to add per device", + required = true, multiValued = false) + String flows = null; + + @Argument(index = 1, name = "numOfRuns", description = "Number of iterations", + required = true, multiValued = false) + String numOfRuns = null; + + @Override + protected void execute() { + FlowRuleService flowService = get(FlowRuleService.class); + DeviceService deviceService = get(DeviceService.class); + CoreService coreService = get(CoreService.class); + + ApplicationId appId = coreService.registerApplication("onos.test.flow.installer"); + + int flowsPerDevice = Integer.parseInt(flows); + int num = Integer.parseInt(numOfRuns); + + ArrayList<Long> results = Lists.newArrayList(); + Iterable<Device> devices = deviceService.getDevices(); + TrafficTreatment treatment = DefaultTrafficTreatment.builder() + .setOutput(PortNumber.portNumber(RandomUtils.nextInt())).build(); + TrafficSelector.Builder sbuilder; + FlowRuleOperations.Builder rules = FlowRuleOperations.builder(); + FlowRuleOperations.Builder remove = FlowRuleOperations.builder(); + + for (Device d : devices) { + for (int i = 0; i < flowsPerDevice; i++) { + sbuilder = DefaultTrafficSelector.builder(); + + sbuilder.matchEthSrc(MacAddress.valueOf(RandomUtils.nextInt() * i)) + .matchEthDst(MacAddress.valueOf((Integer.MAX_VALUE - i) * RandomUtils.nextInt())); + + + int randomPriority = RandomUtils.nextInt(); + + FlowRule addRule = DefaultFlowRule.builder() + .forDevice(d.id()) + .withSelector(sbuilder.build()) + .withTreatment(treatment) + .withPriority(randomPriority) + .fromApp(appId) + .makeTemporary(10) + .build(); + FlowRule removeRule = DefaultFlowRule.builder() + .forDevice(d.id()) + .withSelector(sbuilder.build()) + .withTreatment(treatment) + .withPriority(randomPriority) + .fromApp(appId) + .makeTemporary(10) + .build(); + + rules.add(addRule); + remove.remove(removeRule); + + } + } + + for (int i = 0; i < num; i++) { + latch = new CountDownLatch(2); + flowService.apply(rules.build(new FlowRuleOperationsContext() { + + private final Stopwatch timer = Stopwatch.createStarted(); + + @Override + public void onSuccess(FlowRuleOperations ops) { + + timer.stop(); + results.add(timer.elapsed(TimeUnit.MILLISECONDS)); + if (results.size() == num) { + if (outputJson()) { + print("%s", json(new ObjectMapper(), true, results)); + } else { + printTime(true, results); + } + } + latch.countDown(); + } + })); + + flowService.apply(remove.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + latch.countDown(); + } + })); + try { + latch.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + } + + private Object json(ObjectMapper mapper, boolean isSuccess, ArrayList<Long> elapsed) { + ObjectNode result = mapper.createObjectNode(); + result.put("Success", isSuccess); + ArrayNode node = result.putArray("elapsed-time"); + for (Long v : elapsed) { + node.add(v); + } + return result; + } + + private void printTime(boolean isSuccess, ArrayList<Long> elapsed) { + print("Run is %s.", isSuccess ? "success" : "failure"); + for (int i = 0; i < elapsed.size(); i++) { + print(" Run %s : %s", i, elapsed.get(i)); + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddressBindingsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddressBindingsListCommand.java new file mode 100644 index 00000000..3ce45b90 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AddressBindingsListCommand.java @@ -0,0 +1,69 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import com.google.common.collect.Lists; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cli.Comparators; +import org.onosproject.net.host.HostService; +import org.onosproject.net.host.InterfaceIpAddress; +import org.onosproject.net.host.PortAddresses; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +/** + * Lists all configured address port bindings. + */ +@Command(scope = "onos", name = "address-bindings", + description = "Lists all configured address port bindings.") +public class AddressBindingsListCommand extends AbstractShellCommand { + + private static final String FORMAT = + "port=%s/%s, ip(s)=%s, mac=%s, vlan=%s"; + + @Override + protected void execute() { + HostService hostService = get(HostService.class); + + List<PortAddresses> addresses = + Lists.newArrayList(hostService.getAddressBindings()); + + Collections.sort(addresses, Comparators.ADDRESSES_COMPARATOR); + + for (PortAddresses pa : addresses) { + print(FORMAT, pa.connectPoint().deviceId(), pa.connectPoint().port(), + printIpAddresses(pa.ipAddresses()), pa.mac(), pa.vlan()); + } + } + + private String printIpAddresses(Set<InterfaceIpAddress> addresses) { + StringBuilder output = new StringBuilder("["); + for (InterfaceIpAddress address : addresses) { + output.append(address.ipAddress().toString()); + output.append("/"); + output.append(address.subnetAddress().prefixLength()); + output.append(", "); + } + // Remove the last comma + output.delete(output.length() - 2 , output.length()); + output.append("]"); + return output.toString(); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AnnotateDeviceCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AnnotateDeviceCommand.java new file mode 100644 index 00000000..113fe316 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/AnnotateDeviceCommand.java @@ -0,0 +1,104 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.MastershipRole; +import org.onosproject.net.device.DefaultDeviceDescription; +import org.onosproject.net.device.DeviceDescription; +import org.onosproject.net.device.DeviceProvider; +import org.onosproject.net.device.DeviceProviderRegistry; +import org.onosproject.net.device.DeviceProviderService; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.provider.AbstractProvider; +import org.onosproject.net.provider.ProviderId; + +/** + * Annotates network device model. + */ +@Command(scope = "onos", name = "annotate-device", + description = "Annotates network model entities") +public class AnnotateDeviceCommand extends AbstractShellCommand { + + static final ProviderId PID = new ProviderId("cli", "org.onosproject.cli", true); + + @Argument(index = 0, name = "uri", description = "Device ID", + required = true, multiValued = false) + String uri = null; + + @Argument(index = 1, name = "key", description = "Annotation key", + required = true, multiValued = false) + String key = null; + + @Argument(index = 2, name = "value", + description = "Annotation value (null to remove)", + required = false, multiValued = false) + String value = null; + + @Override + protected void execute() { + DeviceService service = get(DeviceService.class); + Device device = service.getDevice(DeviceId.deviceId(uri)); + + DeviceProviderRegistry registry = get(DeviceProviderRegistry.class); + DeviceProvider provider = new AnnotationProvider(); + try { + DeviceProviderService providerService = registry.register(provider); + providerService.deviceConnected(device.id(), description(device, key, value)); + } finally { + registry.unregister(provider); + } + } + + private DeviceDescription description(Device device, String key, String value) { + DefaultAnnotations.Builder builder = DefaultAnnotations.builder(); + if (value != null) { + builder.set(key, value); + } else { + builder.remove(key); + } + return new DefaultDeviceDescription(device.id().uri(), device.type(), + device.manufacturer(), device.hwVersion(), + device.swVersion(), device.serialNumber(), + device.chassisId(), builder.build()); + } + + // Token provider entity + private static final class AnnotationProvider + extends AbstractProvider implements DeviceProvider { + private AnnotationProvider() { + super(PID); + } + + @Override + public void triggerProbe(DeviceId deviceId) { + } + + @Override + public void roleChanged(DeviceId deviceId, MastershipRole newRole) { + } + + @Override + public boolean isReachable(DeviceId deviceId) { + return false; + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ClusterDevicesCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ClusterDevicesCommand.java new file mode 100644 index 00000000..88c8a8bd --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ClusterDevicesCommand.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.Lists; +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.Comparators; +import org.onosproject.net.DeviceId; +import org.onosproject.net.topology.TopologyCluster; + +import java.util.Collections; +import java.util.List; + +import static org.onosproject.cli.MastersListCommand.json; +import static org.onosproject.net.topology.ClusterId.clusterId; + +/** + * Lists devices of the specified topology cluster in the current topology. + */ +@Command(scope = "onos", name = "cluster-devices", + description = "Lists devices of the specified topology cluster in the current topology") +public class ClusterDevicesCommand extends ClustersListCommand { + + @Argument(index = 0, name = "id", description = "Cluster ID", + required = true, multiValued = false) + String id = null; + + @Override + protected void execute() { + int cid = Integer.parseInt(id); + init(); + TopologyCluster cluster = service.getCluster(topology, clusterId(cid)); + if (cluster == null) { + error("No such cluster %s", cid); + } else { + List<DeviceId> ids = Lists.newArrayList(service.getClusterDevices(topology, cluster)); + Collections.sort(ids, Comparators.ELEMENT_ID_COMPARATOR); + if (outputJson()) { + print("%s", json(new ObjectMapper(), ids)); + } else { + for (DeviceId deviceId : ids) { + print("%s", deviceId); + } + } + } + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ClusterIdCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ClusterIdCompleter.java new file mode 100644 index 00000000..73e8acba --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ClusterIdCompleter.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.topology.Topology; +import org.onosproject.net.topology.TopologyCluster; +import org.onosproject.net.topology.TopologyService; + +import java.util.List; +import java.util.SortedSet; + +/** + * Cluster ID completer. + */ +public class ClusterIdCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + + // Fetch our service and feed it's offerings to the string completer + TopologyService service = AbstractShellCommand.get(TopologyService.class); + Topology topology = service.currentTopology(); + + SortedSet<String> strings = delegate.getStrings(); + for (TopologyCluster cluster : service.getClusters(topology)) { + strings.add(Integer.toString(cluster.id().index())); + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ClusterLinksCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ClusterLinksCommand.java new file mode 100644 index 00000000..dc63bff9 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ClusterLinksCommand.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.net.Link; +import org.onosproject.net.topology.TopologyCluster; + +import static org.onosproject.cli.net.LinksListCommand.json; +import static org.onosproject.cli.net.LinksListCommand.linkString; +import static org.onosproject.net.topology.ClusterId.clusterId; + +/** + * Lists links of the specified topology cluster in the current topology. + */ +@Command(scope = "onos", name = "cluster-links", + description = "Lists links of the specified topology cluster in the current topology") +public class ClusterLinksCommand extends ClustersListCommand { + + @Argument(index = 0, name = "id", description = "Cluster ID", + required = true, multiValued = false) + String id = null; + + @Override + protected void execute() { + int cid = Integer.parseInt(id); + init(); + TopologyCluster cluster = service.getCluster(topology, clusterId(cid)); + if (cluster == null) { + error("No such cluster %s", cid); + } else if (outputJson()) { + print("%s", json(this, service.getClusterLinks(topology, cluster))); + } else { + for (Link link : service.getClusterLinks(topology, cluster)) { + print(linkString(link)); + } + } + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ClustersListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ClustersListCommand.java new file mode 100644 index 00000000..21c27324 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ClustersListCommand.java @@ -0,0 +1,66 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.google.common.collect.Lists; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.Comparators; +import org.onosproject.net.topology.TopologyCluster; + +import java.util.Collections; +import java.util.List; + +/** + * Lists all clusters in the current topology. + */ +@Command(scope = "onos", name = "clusters", + description = "Lists all clusters in the current topology") +public class ClustersListCommand extends TopologyCommand { + + private static final String FMT = + "id=%d, devices=%d, links=%d"; + + @Override + protected void execute() { + init(); + List<TopologyCluster> clusters = Lists.newArrayList(service.getClusters(topology)); + Collections.sort(clusters, Comparators.CLUSTER_COMPARATOR); + + if (outputJson()) { + print("%s", json(clusters)); + } else { + for (TopologyCluster cluster : clusters) { + print(FMT, cluster.id().index(), cluster.deviceCount(), cluster.linkCount()); + } + } + } + + // Produces a JSON result. + private JsonNode json(Iterable<TopologyCluster> clusters) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode result = mapper.createArrayNode(); + + clusters.spliterator() + .forEachRemaining(cluster -> + result.add(jsonForEntity(cluster, TopologyCluster.class))); + + return result; + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ConnectPointCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ConnectPointCompleter.java new file mode 100644 index 00000000..5e2727cf --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ConnectPointCompleter.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.Device; +import org.onosproject.net.Port; +import org.onosproject.net.device.DeviceService; + +import java.util.List; +import java.util.SortedSet; + +/** + * ConnectPoint completer. + */ +public class ConnectPointCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + + // Fetch our service and feed it's offerings to the string completer + DeviceService service = AbstractShellCommand.get(DeviceService.class); + + // Generate the device ID/port number identifiers + for (Device device : service.getDevices()) { + SortedSet<String> strings = delegate.getStrings(); + for (Port port : service.getPorts(device.id())) { + if (!port.number().isLogical()) { + strings.add(device.id().toString() + "/" + port.number()); + } + } + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ConnectivityIntentCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ConnectivityIntentCommand.java new file mode 100644 index 00000000..6c33f45c --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ConnectivityIntentCommand.java @@ -0,0 +1,403 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static org.onosproject.net.flow.DefaultTrafficTreatment.builder; + +import java.util.LinkedList; +import java.util.List; + +import org.apache.karaf.shell.commands.Option; +import org.onlab.packet.Ip6Address; +import org.onlab.packet.IpAddress; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.TpPort; +import org.onlab.packet.VlanId; +import org.onlab.util.Bandwidth; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.Link; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.Key; +import org.onosproject.net.intent.constraint.BandwidthConstraint; +import org.onosproject.net.intent.constraint.LambdaConstraint; +import org.onosproject.net.intent.constraint.LinkTypeConstraint; +import org.onosproject.net.intent.constraint.PartialFailureConstraint; +import org.onosproject.net.resource.link.BandwidthResource; + +/** + * Base class for command line operations for connectivity based intents. + */ +public abstract class ConnectivityIntentCommand extends AbstractShellCommand { + + // Selectors + @Option(name = "-s", aliases = "--ethSrc", description = "Source MAC Address", + required = false, multiValued = false) + private String srcMacString = null; + + @Option(name = "-d", aliases = "--ethDst", description = "Destination MAC Address", + required = false, multiValued = false) + private String dstMacString = null; + + @Option(name = "-t", aliases = "--ethType", description = "Ethernet Type", + required = false, multiValued = false) + private String ethTypeString = null; + + @Option(name = "-v", aliases = "--vlan", description = "VLAN ID", + required = false, multiValued = false) + private String vlanString = null; + + @Option(name = "--ipProto", description = "IP Protocol", + required = false, multiValued = false) + private String ipProtoString = null; + + @Option(name = "--ipSrc", description = "Source IP Prefix", + required = false, multiValued = false) + private String srcIpString = null; + + @Option(name = "--ipDst", description = "Destination IP Prefix", + required = false, multiValued = false) + private String dstIpString = null; + + @Option(name = "--fLabel", description = "IPv6 Flow Label", + required = false, multiValued = false) + private String fLabelString = null; + + @Option(name = "--icmp6Type", description = "ICMPv6 Type", + required = false, multiValued = false) + private String icmp6TypeString = null; + + @Option(name = "--icmp6Code", description = "ICMPv6 Code", + required = false, multiValued = false) + private String icmp6CodeString = null; + + @Option(name = "--ndTarget", description = "IPv6 Neighbor Discovery Target Address", + required = false, multiValued = false) + private String ndTargetString = null; + + @Option(name = "--ndSLL", description = "IPv6 Neighbor Discovery Source Link-Layer", + required = false, multiValued = false) + private String ndSLLString = null; + + @Option(name = "--ndTLL", description = "IPv6 Neighbor Discovery Target Link-Layer", + required = false, multiValued = false) + private String ndTLLString = null; + + @Option(name = "--tcpSrc", description = "Source TCP Port", + required = false, multiValued = false) + private String srcTcpString = null; + + @Option(name = "--tcpDst", description = "Destination TCP Port", + required = false, multiValued = false) + private String dstTcpString = null; + + @Option(name = "--extHdr", description = "IPv6 Extension Header Pseudo-field", + required = false, multiValued = true) + private List<String> extHdrStringList = null; + + @Option(name = "-b", aliases = "--bandwidth", description = "Bandwidth", + required = false, multiValued = false) + private String bandwidthString = null; + + @Option(name = "-l", aliases = "--lambda", description = "Lambda", + required = false, multiValued = false) + private boolean lambda = false; + + @Option(name = "-a", aliases = "--appId", description = "Application Id", + required = false, multiValued = false) + private String appId = null; + + @Option(name = "-k", aliases = "--key", description = "Intent Key", + required = false, multiValued = false) + private String intentKey = null; + + @Option(name = "--partial", description = "Allow partial installation", + required = false, multiValued = false) + private boolean partial = false; + + + // Treatments + @Option(name = "--setEthSrc", description = "Rewrite Source MAC Address", + required = false, multiValued = false) + private String setEthSrcString = null; + + @Option(name = "--setEthDst", description = "Rewrite Destination MAC Address", + required = false, multiValued = false) + private String setEthDstString = null; + + @Option(name = "--setIpSrc", description = "Rewrite Source IP Address", + required = false, multiValued = false) + private String setIpSrcString = null; + + @Option(name = "--setIpDst", description = "Rewrite Destination IP Address", + required = false, multiValued = false) + private String setIpDstString = null; + + @Option(name = "--setVlan", description = "Rewrite VLAN ID", + required = false, multiValued = false) + private String setVlan = null; + + @Option(name = "--popVlan", description = "Pop VLAN Tag", + required = false, multiValued = false) + private boolean popVlan = false; + + @Option(name = "--pushVlan", description = "Push VLAN ID", + required = false, multiValued = false) + private String pushVlan = null; + + // Priorities + @Option(name = "-p", aliases = "--priority", description = "Priority", + required = false, multiValued = false) + private int priority = Intent.DEFAULT_INTENT_PRIORITY; + + /** + * Constructs a traffic selector based on the command line arguments + * presented to the command. + * @return traffic selector + */ + protected TrafficSelector buildTrafficSelector() { + IpPrefix srcIpPrefix = null; + IpPrefix dstIpPrefix = null; + + TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); + + if (!isNullOrEmpty(srcIpString)) { + srcIpPrefix = IpPrefix.valueOf(srcIpString); + if (srcIpPrefix.isIp4()) { + selectorBuilder.matchIPSrc(srcIpPrefix); + } else { + selectorBuilder.matchIPv6Src(srcIpPrefix); + } + } + + if (!isNullOrEmpty(dstIpString)) { + dstIpPrefix = IpPrefix.valueOf(dstIpString); + if (dstIpPrefix.isIp4()) { + selectorBuilder.matchIPDst(dstIpPrefix); + } else { + selectorBuilder.matchIPv6Dst(dstIpPrefix); + } + } + + if ((srcIpPrefix != null) && (dstIpPrefix != null) && + (srcIpPrefix.version() != dstIpPrefix.version())) { + // ERROR: IP src/dst version mismatch + throw new IllegalArgumentException( + "IP source and destination version mismatch"); + } + + // + // Set the default EthType based on the IP version if the matching + // source or destination IP prefixes. + // + Short ethType = null; + if ((srcIpPrefix != null) && srcIpPrefix.isIp6()) { + ethType = EthType.IPV6.value(); + } + if ((dstIpPrefix != null) && dstIpPrefix.isIp6()) { + ethType = EthType.IPV6.value(); + } + if (!isNullOrEmpty(ethTypeString)) { + ethType = EthType.parseFromString(ethTypeString); + } + if (ethType != null) { + selectorBuilder.matchEthType(ethType); + } + if (!isNullOrEmpty(vlanString)) { + selectorBuilder.matchVlanId(VlanId.vlanId(Short.parseShort(vlanString))); + } + if (!isNullOrEmpty(srcMacString)) { + selectorBuilder.matchEthSrc(MacAddress.valueOf(srcMacString)); + } + + if (!isNullOrEmpty(dstMacString)) { + selectorBuilder.matchEthDst(MacAddress.valueOf(dstMacString)); + } + + if (!isNullOrEmpty(ipProtoString)) { + short ipProtoShort = IpProtocol.parseFromString(ipProtoString); + selectorBuilder.matchIPProtocol((byte) ipProtoShort); + } + + if (!isNullOrEmpty(fLabelString)) { + selectorBuilder.matchIPv6FlowLabel(Integer.parseInt(fLabelString)); + } + + if (!isNullOrEmpty(icmp6TypeString)) { + byte icmp6Type = Icmp6Type.parseFromString(icmp6TypeString); + selectorBuilder.matchIcmpv6Type(icmp6Type); + } + + if (!isNullOrEmpty(icmp6CodeString)) { + byte icmp6Code = Icmp6Code.parseFromString(icmp6CodeString); + selectorBuilder.matchIcmpv6Code(icmp6Code); + } + + if (!isNullOrEmpty(ndTargetString)) { + selectorBuilder.matchIPv6NDTargetAddress(Ip6Address.valueOf(ndTargetString)); + } + + if (!isNullOrEmpty(ndSLLString)) { + selectorBuilder.matchIPv6NDSourceLinkLayerAddress(MacAddress.valueOf(ndSLLString)); + } + + if (!isNullOrEmpty(ndTLLString)) { + selectorBuilder.matchIPv6NDTargetLinkLayerAddress(MacAddress.valueOf(ndTLLString)); + } + + if (!isNullOrEmpty(srcTcpString)) { + selectorBuilder.matchTcpSrc(TpPort.tpPort(Integer.parseInt(srcTcpString))); + } + + if (!isNullOrEmpty(dstTcpString)) { + selectorBuilder.matchTcpDst(TpPort.tpPort(Integer.parseInt(dstTcpString))); + } + + if (extHdrStringList != null) { + short extHdr = 0; + for (String extHdrString : extHdrStringList) { + extHdr = (short) (extHdr | ExtHeader.parseFromString(extHdrString)); + } + selectorBuilder.matchIPv6ExthdrFlags(extHdr); + } + + return selectorBuilder.build(); + } + + /** + * Generates a traffic treatment for this intent based on command line + * arguments presented to the command. + * + * @return traffic treatment + */ + protected TrafficTreatment buildTrafficTreatment() { + final TrafficTreatment.Builder treatmentBuilder = builder(); + boolean emptyTreatment = true; + + if (!isNullOrEmpty(setEthSrcString)) { + treatmentBuilder.setEthSrc(MacAddress.valueOf(setEthSrcString)); + emptyTreatment = false; + } + + if (!isNullOrEmpty(setEthDstString)) { + treatmentBuilder.setEthDst(MacAddress.valueOf(setEthDstString)); + emptyTreatment = false; + } + + if (!isNullOrEmpty(setIpSrcString)) { + treatmentBuilder.setIpSrc(IpAddress.valueOf(setIpSrcString)); + emptyTreatment = false; + } + + if (!isNullOrEmpty(setIpDstString)) { + treatmentBuilder.setIpSrc(IpAddress.valueOf(setIpDstString)); + emptyTreatment = false; + } + if (!isNullOrEmpty(setVlan)) { + treatmentBuilder.setVlanId(VlanId.vlanId(Short.parseShort(setVlan))); + emptyTreatment = false; + } + if (popVlan) { + treatmentBuilder.popVlan(); + emptyTreatment = false; + } + if (!isNullOrEmpty(pushVlan)) { + treatmentBuilder.pushVlan(); + treatmentBuilder.setVlanId(VlanId.vlanId(Short.parseShort(pushVlan))); + emptyTreatment = false; + } + + if (emptyTreatment) { + return DefaultTrafficTreatment.emptyTreatment(); + } else { + return treatmentBuilder.build(); + } + } + + /** + * Builds the constraint list for this command based on the command line + * parameters. + * + * @return List of constraint objects describing the constraints requested + */ + protected List<Constraint> buildConstraints() { + final List<Constraint> constraints = new LinkedList<>(); + + // Check for a bandwidth specification + if (!isNullOrEmpty(bandwidthString)) { + final Bandwidth bandwidth = Bandwidth.bps(Double.parseDouble(bandwidthString)); + constraints.add(new BandwidthConstraint(new BandwidthResource(bandwidth))); + } + + // Check for a lambda specification + if (lambda) { + constraints.add(new LambdaConstraint(null)); + } + constraints.add(new LinkTypeConstraint(lambda, Link.Type.OPTICAL)); + + if (partial) { + constraints.add(new PartialFailureConstraint()); + } + + return constraints; + } + + @Override + protected ApplicationId appId() { + ApplicationId appIdForIntent; + if (appId == null) { + appIdForIntent = super.appId(); + } else { + CoreService service = get(CoreService.class); + appIdForIntent = service.getAppId(appId); + } + return appIdForIntent; + } + + /** + * Creates a key for an intent based on command line arguments. If a key + * has been specified, it is returned. If no key is specified, null + * is returned. + * + * @return intent key if specified, null otherwise + */ + protected Key key() { + Key key = null; + ApplicationId appIdForIntent; + + if (intentKey != null) { + key = Key.of(intentKey, appId()); + } + return key; + } + + /** + * Gets the priority to use for the intent. + * + * @return priority + */ + protected int priority() { + return priority; + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/CountersListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/CountersListCommand.java new file mode 100644 index 00000000..a44fdc9f --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/CountersListCommand.java @@ -0,0 +1,107 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import java.util.Map; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.store.service.StorageAdminService; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Command to list the various counters in the system. + */ +@Command(scope = "onos", name = "counters", + description = "Lists information about atomic counters in the system") +public class CountersListCommand extends AbstractShellCommand { + + private static final String FMT = "name=%s value=%d"; + + /** + * Displays counters as text. + * + * @param counters counter info + */ + private void displayCounters(Map<String, Long> counters) { + counters.forEach((name, value) -> print(FMT, name, value)); + } + + /** + * Converts info for counters into a JSON object. + * + * @param counters counter info + */ + private JsonNode json(Map<String, Long> counters) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode jsonCounters = mapper.createArrayNode(); + + // Create a JSON node for each counter + counters.forEach((name, value) -> { + ObjectNode jsonCounter = mapper.createObjectNode(); + jsonCounter.put("name", name) + .put("value", value); + jsonCounters.add(jsonCounter); + }); + + return jsonCounters; + } + + /** + * Converts info for counters from different databases into a JSON object. + * + * @param partitionedDbCounters counters info + * @param inMemoryDbCounters counters info + */ + private JsonNode jsonAllCounters(Map<String, Long> partitionedDbCounters, + Map<String, Long> inMemoryDbCounters) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode jsonCounters = mapper.createArrayNode(); + + // Create a JSON node for partitioned database counter + ObjectNode jsonPartitionedDatabaseCounters = mapper.createObjectNode(); + jsonPartitionedDatabaseCounters.set("partitionedDatabaseCounters", + json(partitionedDbCounters)); + jsonCounters.add(jsonPartitionedDatabaseCounters); + // Create a JSON node for in-memory database counter + ObjectNode jsonInMemoryDatabseCounters = mapper.createObjectNode(); + jsonInMemoryDatabseCounters.set("inMemoryDatabaseCounters", + json(inMemoryDbCounters)); + jsonCounters.add(jsonInMemoryDatabseCounters); + + return jsonCounters; + } + + + @Override + protected void execute() { + StorageAdminService storageAdminService = get(StorageAdminService.class); + Map<String, Long> partitionedDatabaseCounters = storageAdminService.getPartitionedDatabaseCounters(); + Map<String, Long> inMemoryDatabaseCounters = storageAdminService.getInMemoryDatabaseCounters(); + if (outputJson()) { + print("%s", jsonAllCounters(partitionedDatabaseCounters, inMemoryDatabaseCounters)); + } else { + print("Partitioned database counters:"); + displayCounters(partitionedDatabaseCounters); + print("In-memory database counters:"); + displayCounters(inMemoryDatabaseCounters); + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceIdCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceIdCompleter.java new file mode 100644 index 00000000..82ef5edf --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceIdCompleter.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.Device; +import org.onosproject.net.device.DeviceService; + +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; + +/** + * Device ID completer. + */ +public class DeviceIdCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + + // Fetch our service and feed it's offerings to the string completer + DeviceService service = AbstractShellCommand.get(DeviceService.class); + Iterator<Device> it = service.getDevices().iterator(); + SortedSet<String> strings = delegate.getStrings(); + while (it.hasNext()) { + strings.add(it.next().id().toString()); + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DevicePortStatsCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DevicePortStatsCommand.java new file mode 100644 index 00000000..2e804545 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DevicePortStatsCommand.java @@ -0,0 +1,192 @@ +package org.onosproject.cli.net; + +/* + * Copyright 2015 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. + */ + +import static org.onosproject.net.DeviceId.deviceId; + +import java.util.concurrent.TimeUnit; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.device.PortStatistics; + +/** + * Lists port statistic of all ports in the system. + */ +@Command(scope = "onos", name = "portstats", + description = "Lists statistics of all ports in the system") +public class DevicePortStatsCommand extends DevicesListCommand { + + @Option(name = "-d", aliases = "--delta", description = "Show Delta Port Statistics," + + "only for the last polling interval", + required = false, multiValued = false) + private boolean delta = false; + + @Option(name = "-t", aliases = "--table", description = "Show human readable table format for statistics", + required = false, multiValued = false) + private boolean table = false; + + @Argument(index = 0, name = "uri", description = "Device ID", + required = false, multiValued = false) + String uri = null; + + private static final String FORMAT = + " port=%s, pktRx=%s, pktTx=%s, bytesRx=%s, bytesTx=%s, pktRxDrp=%s, pktTxDrp=%s, Dur=%s"; + + @Override + protected void execute() { + DeviceService deviceService = get(DeviceService.class); + + if (uri == null) { + for (Device d : getSortedDevices(deviceService)) { + if (delta) { + if (table) { + printPortStatsDeltaTable(d.id(), deviceService.getPortDeltaStatistics(d.id())); + } else { + printPortStatsDelta(d.id(), deviceService.getPortDeltaStatistics(d.id())); + } + } else { + printPortStats(d.id(), deviceService.getPortStatistics(d.id())); + } + } + } else { + Device d = deviceService.getDevice(deviceId(uri)); + if (d == null) { + error("No such device %s", uri); + } else if (delta) { + if (table) { + printPortStatsDeltaTable(d.id(), deviceService.getPortDeltaStatistics(d.id())); + } else { + printPortStatsDelta(d.id(), deviceService.getPortDeltaStatistics(d.id())); + } + } else { + printPortStats(d.id(), deviceService.getPortStatistics(d.id())); + } + } + } + + /** + * Prints Port Statistics. + * + * @param deviceId + * @param portStats + */ + private void printPortStats(DeviceId deviceId, Iterable<PortStatistics> portStats) { + + print("deviceId=%s", deviceId); + for (PortStatistics stat : portStats) { + print(FORMAT, stat.port(), stat.packetsReceived(), stat.packetsSent(), stat.bytesReceived(), + stat.bytesSent(), stat.packetsRxDropped(), stat.packetsTxDropped(), stat.durationSec()); + } + } + /** + * Prints Port delta statistics. + * + * @param deviceId + * @param portStats + */ + private void printPortStatsDelta(DeviceId deviceId, Iterable<PortStatistics> portStats) { + final String formatDelta = " port=%s, pktRx=%s, pktTx=%s, bytesRx=%s, bytesTx=%s," + + " rateRx=%s, rateTx=%s, pktRxDrp=%s, pktTxDrp=%s, interval=%s"; + print("deviceId=%s", deviceId); + for (PortStatistics stat : portStats) { + float duration = ((float) stat.durationSec()) + + (((float) stat.durationNano()) / TimeUnit.SECONDS.toNanos(1)); + float rateRx = stat.bytesReceived() * 8 / duration; + float rateTx = stat.bytesSent() * 8 / duration; + print(formatDelta, stat.port(), + stat.packetsReceived(), + stat.packetsSent(), + stat.bytesReceived(), + stat.bytesSent(), + String.format("%.1f", rateRx), + String.format("%.1f", rateTx), + stat.packetsRxDropped(), + stat.packetsTxDropped(), + String.format("%.3f", duration)); + } + } + + /** + * Prints human readable table with delta Port Statistics for specific device. + * + * @param deviceId + * @param portStats + */ + private void printPortStatsDeltaTable(DeviceId deviceId, Iterable<PortStatistics> portStats) { + final String formatDeltaTable = "|%5s | %7s | %7s | %7s | %7s | %7s | %7s | %7s | %7s |%9s |"; + print("+---------------------------------------------------------------------------------------------------+"); + print("| DeviceId = %s |", deviceId); + print("|---------------------------------------------------------------------------------------------------|"); + print("| | Receive | Transmit | Time [s] |"); + print("| Port | Packets | Bytes | Rate bps | Drop | Packets | Bytes | Rate bps | Drop | Interval |"); + print("|---------------------------------------------------------------------------------------------------|"); + + for (PortStatistics stat : portStats) { + float duration = ((float) stat.durationSec()) + + (((float) stat.durationNano()) / TimeUnit.SECONDS.toNanos(1)); + float rateRx = stat.bytesReceived() * 8 / duration; + float rateTx = stat.bytesSent() * 8 / duration; + print(formatDeltaTable, stat.port(), + humanReadable(stat.packetsReceived()), + humanReadable(stat.bytesReceived()), + humanReadableBps(rateRx), + humanReadable(stat.packetsRxDropped()), + humanReadable(stat.packetsSent()), + humanReadable(stat.bytesSent()), + humanReadableBps(rateTx), + humanReadable(stat.packetsTxDropped()), + String.format("%.3f", duration)); + } + print("+---------------------------------------------------------------------------------------------------+"); + } + + /** + * Converts bytes to human readable string with Kilo, Mega, Giga, etc. + * + * @param bytes input byte array + * @return human readble string + */ + public static String humanReadable(long bytes) { + int unit = 1000; + if (bytes < unit) { + return String.format("%s ", bytes); + } + int exp = (int) (Math.log(bytes) / Math.log(unit)); + Character pre = ("KMGTPE").charAt(exp - 1); + return String.format("%.2f%s", bytes / Math.pow(unit, exp), pre); + } + /** + * Converts bps to human readable format. + * + * @param bps input rate + * @return human readble string + */ + public static String humanReadableBps(float bps) { + int unit = 1000; + if (bps < unit) { + return String.format("%.0f ", (float) bps); + } + int exp = (int) (Math.log(bps) / Math.log(unit)); + Character pre = ("KMGTPE").charAt(exp - 1); + return String.format("%.2f%s", bps / Math.pow(unit, exp), pre); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java new file mode 100644 index 00000000..494273cc --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DevicePortsListCommand.java @@ -0,0 +1,149 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onosproject.cli.Comparators; +import org.onosproject.net.Device; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.device.DeviceService; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.onosproject.net.DeviceId.deviceId; + +/** + * Lists all ports or all ports of a device. + */ +@Command(scope = "onos", name = "ports", + description = "Lists all ports or all ports of a device") +public class DevicePortsListCommand extends DevicesListCommand { + + private static final String FMT = " port=%s, state=%s, type=%s, speed=%s%s"; + + @Option(name = "-e", aliases = "--enabled", description = "Show only enabled ports", + required = false, multiValued = false) + private boolean enabled = false; + + @Option(name = "-d", aliases = "--disabled", description = "Show only disabled ports", + required = false, multiValued = false) + private boolean disabled = false; + + @Argument(index = 0, name = "uri", description = "Device ID", + required = false, multiValued = false) + String uri = null; + + @Override + protected void execute() { + DeviceService service = get(DeviceService.class); + if (uri == null) { + if (outputJson()) { + print("%s", jsonPorts(service, getSortedDevices(service))); + } else { + for (Device device : getSortedDevices(service)) { + printDevice(service, device); + } + } + + } else { + Device device = service.getDevice(deviceId(uri)); + if (device == null) { + error("No such device %s", uri); + } else if (outputJson()) { + print("%s", jsonPorts(service, new ObjectMapper(), device)); + } else { + printDevice(service, device); + } + } + } + + /** + * Produces JSON array containing ports of the specified devices. + * + * @param service device service + * @param devices collection of devices + * @return JSON array + */ + public JsonNode jsonPorts(DeviceService service, Iterable<Device> devices) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode result = mapper.createArrayNode(); + for (Device device : devices) { + result.add(jsonPorts(service, mapper, device)); + } + return result; + } + + /** + * Produces JSON array containing ports of the specified device. + * + * @param service device service + * @param mapper object mapper + * @param device infrastructure devices + * @return JSON array + */ + public JsonNode jsonPorts(DeviceService service, ObjectMapper mapper, Device device) { + ObjectNode result = mapper.createObjectNode(); + ArrayNode ports = mapper.createArrayNode(); + for (Port port : service.getPorts(device.id())) { + if (isIncluded(port)) { + ports.add(mapper.createObjectNode() + .put("port", portName(port.number())) + .put("isEnabled", port.isEnabled()) + .put("type", port.type().toString().toLowerCase()) + .put("portSpeed", port.portSpeed()) + .set("annotations", annotations(mapper, port.annotations()))); + } + } + result.set("device", jsonForEntity(device, Device.class)); + result.set("ports", ports); + return result; + } + + private String portName(PortNumber port) { + return port.equals(PortNumber.LOCAL) ? "local" : port.toString(); + } + + // Determines if a port should be included in output. + private boolean isIncluded(Port port) { + return enabled && port.isEnabled() || disabled && !port.isEnabled() || + !enabled && !disabled; + } + + @Override + protected void printDevice(DeviceService service, Device device) { + super.printDevice(service, device); + List<Port> ports = new ArrayList<>(service.getPorts(device.id())); + Collections.sort(ports, Comparators.PORT_COMPARATOR); + for (Port port : ports) { + if (isIncluded(port)) { + print(FMT, portName(port.number()), + port.isEnabled() ? "enabled" : "disabled", + port.type().toString().toLowerCase(), port.portSpeed(), + annotations(port.annotations())); + } + } + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceRemoveCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceRemoveCommand.java new file mode 100644 index 00000000..1226e436 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceRemoveCommand.java @@ -0,0 +1,40 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.DeviceId; +import org.onosproject.net.device.DeviceAdminService; + +/** + * Removes an infrastructure device. + */ +@Command(scope = "onos", name = "device-remove", + description = "Removes an infrastructure device") +public class DeviceRemoveCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "uri", description = "Device ID", + required = true, multiValued = false) + String uri = null; + + @Override + protected void execute() { + get(DeviceAdminService.class).removeDevice(DeviceId.deviceId(uri)); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceRoleCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceRoleCommand.java new file mode 100644 index 00000000..17fc87a3 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DeviceRoleCommand.java @@ -0,0 +1,55 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cluster.NodeId; +import org.onosproject.mastership.MastershipAdminService; +import org.onosproject.net.MastershipRole; + +import com.google.common.util.concurrent.Futures; + +import static org.onosproject.net.DeviceId.deviceId; + +/** + * Sets role of the controller node for the given infrastructure device. + */ +@Command(scope = "onos", name = "device-role", + description = "Sets role of the controller node for the given infrastructure device") +public class DeviceRoleCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "uri", description = "Device ID", + required = true, multiValued = false) + String uri = null; + + @Argument(index = 1, name = "node", description = "Node ID", + required = true, multiValued = false) + String node = null; + + @Argument(index = 2, name = "role", description = "Mastership role", + required = true, multiValued = false) + String role = null; + + @Override + protected void execute() { + MastershipAdminService service = get(MastershipAdminService.class); + MastershipRole mastershipRole = MastershipRole.valueOf(role.toUpperCase()); + Futures.getUnchecked(service.setRole(new NodeId(node), deviceId(uri), mastershipRole)); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DevicesListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DevicesListCommand.java new file mode 100644 index 00000000..e40bcad6 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DevicesListCommand.java @@ -0,0 +1,97 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import java.util.Collections; +import java.util.List; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cli.Comparators; +import org.onosproject.net.Device; +import org.onosproject.net.device.DeviceService; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; + +import static com.google.common.collect.Lists.newArrayList; + +/** + * Lists all infrastructure devices. + */ +@Command(scope = "onos", name = "devices", + description = "Lists all infrastructure devices") +public class DevicesListCommand extends AbstractShellCommand { + + private static final String FMT = + "id=%s, available=%s, role=%s, type=%s, mfr=%s, hw=%s, sw=%s, serial=%s%s"; + + @Override + protected void execute() { + DeviceService service = get(DeviceService.class); + if (outputJson()) { + print("%s", json(getSortedDevices(service))); + } else { + for (Device device : getSortedDevices(service)) { + printDevice(service, device); + } + } + } + + /** + * Returns JSON node representing the specified devices. + * + * @param devices collection of devices + * @return JSON node + */ + private JsonNode json(Iterable<Device> devices) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode result = mapper.createArrayNode(); + for (Device device : devices) { + result.add(jsonForEntity(device, Device.class)); + } + return result; + } + + /** + * Returns the list of devices sorted using the device ID URIs. + * + * @param service device service + * @return sorted device list + */ + public static List<Device> getSortedDevices(DeviceService service) { + List<Device> devices = newArrayList(service.getDevices()); + Collections.sort(devices, Comparators.ELEMENT_COMPARATOR); + return devices; + } + + /** + * Prints information about the specified device. + * + * @param service device service + * @param device infrastructure device + */ + protected void printDevice(DeviceService service, Device device) { + if (device != null) { + print(FMT, device.id(), service.isAvailable(device.id()), + service.getRole(device.id()), device.type(), + device.manufacturer(), device.hwVersion(), device.swVersion(), + device.serialNumber(), annotations(device.annotations())); + } + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DriverNameCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DriverNameCompleter.java new file mode 100644 index 00000000..2ba8a20a --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DriverNameCompleter.java @@ -0,0 +1,44 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.driver.DriverAdminService; + +import java.util.List; +import java.util.SortedSet; + +/** + * Device driver name completer. + */ +public class DriverNameCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + SortedSet<String> strings = delegate.getStrings(); + + // Fetch our service and feed it's offerings to the string completer + DriverAdminService service = AbstractShellCommand.get(DriverAdminService.class); + service.getDrivers().forEach(d -> strings.add(d.name())); + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DriversListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DriversListCommand.java new file mode 100644 index 00000000..05d9e957 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/DriversListCommand.java @@ -0,0 +1,81 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import java.util.Set; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.driver.Driver; +import org.onosproject.net.driver.DriverAdminService; + +import com.fasterxml.jackson.databind.node.ArrayNode; + +/** + * Lists device drivers. + */ +@Command(scope = "onos", name = "drivers", + description = "Lists device drivers") +public class DriversListCommand extends AbstractShellCommand { + + private static final String FMT = "driver=%s, extends=%s, mfr=%s, hw=%s, sw=%s"; + private static final String FMT_B = " %s via %s"; + private static final String FMT_P = " %s=%s"; + + @Argument(index = 0, name = "driverName", description = "Driver name", + required = false, multiValued = false) + String driverName = null; + + @Override + protected void execute() { + DriverAdminService service = get(DriverAdminService.class); + + if (driverName != null) { + printDriver(service.getDriver(driverName)); + } else { + if (outputJson()) { + json(service.getDrivers()); + } else { + service.getDrivers().forEach(this::printDriver); + } + } + } + + private void json(Driver driver) { + print("%s", jsonForEntity(driver, Driver.class)); + } + + private void json(Set<Driver> drivers) { + ArrayNode result = mapper().createArrayNode(); + drivers.forEach(driver -> result.add(jsonForEntity(driver, Driver.class))); + print("%s", result.toString()); + } + + private void printDriver(Driver driver) { + if (outputJson()) { + json(driver); + } else { + Driver parent = driver.parent(); + print(FMT, driver.name(), parent != null ? parent.name() : "none", + driver.manufacturer(), driver.hwVersion(), driver.swVersion()); + driver.behaviours().forEach(b -> print(FMT_B, b.getCanonicalName(), + driver.implementation(b).getCanonicalName())); + driver.properties().forEach((k, v) -> print(FMT_P, k, v)); + } + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/EdgePortsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/EdgePortsListCommand.java new file mode 100644 index 00000000..1a9235e6 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/EdgePortsListCommand.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.edge.EdgePortService; + +import static org.onosproject.net.DeviceId.deviceId; + +/** + * Lists all edge ports. + */ +@Command(scope = "onos", name = "edge-ports", + description = "Lists all edge ports.") +public class EdgePortsListCommand extends AbstractShellCommand { + + private static final String FMT = "%s/%s"; + + @Argument(index = 0, name = "uri", description = "Device ID", + required = false, multiValued = false) + String uri = null; + + + + @Override + protected void execute() { + EdgePortService service = get(EdgePortService.class); + if (uri == null) { + service.getEdgePoints().forEach(e -> print(FMT, e.deviceId(), e.port())); + } else { + service.getEdgePoints(deviceId(uri)).forEach(e -> print(FMT, e.deviceId(), e.port())); + } + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/EthType.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/EthType.java new file mode 100644 index 00000000..02c97b8f --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/EthType.java @@ -0,0 +1,84 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.onlab.packet.Ethernet; + +/** + * Allowed values for Ethernet types. Used by the CLI completer for + * connectivity based intent L2 parameters. + */ +public enum EthType { + /** ARP. */ + ARP(Ethernet.TYPE_ARP), + /** RARP. */ + RARP(Ethernet.TYPE_RARP), + /** IPV4. */ + IPV4(Ethernet.TYPE_IPV4), + /** IPV6. */ + IPV6(Ethernet.TYPE_IPV6), + /** LLDP. */ + LLDP(Ethernet.TYPE_LLDP), + /** BSN. */ + BSN(Ethernet.TYPE_BSN); + + private short value; + + /** + * Constructs an EthType with the given value. + * + * @param value value to use when this EthType is seen + */ + private EthType(short value) { + this.value = value; + } + + /** + * Gets the value to use for this EthType. + * + * @return short value to use for this EthType + */ + public short value() { + return this.value; + } + + /** + * Parse a string input that could contain an EthType value. The value + * may appear in the string either as a known protocol name (one of the + * values of this enum), or a numeric protocol value. + * + * @param input the input string to parse + * @return the numeric value of the parsed Ethernet type + * @throws IllegalArgumentException if the input string does not contain a + * value that can be parsed into an Ethernet type + */ + public static short parseFromString(String input) { + try { + return valueOf(input).value(); + } catch (IllegalArgumentException e) { + // The input is not a known Ethernet type name, let's see if it's an + // Ethernet type value (short). We parse with Integer to handle + // unsigned values correctly. + try { + return (short) Integer.parseInt(input); + } catch (NumberFormatException e1) { + throw new IllegalArgumentException( + "EthType value must be either a string protocol name" + + " or a 16-bit protocol value"); + } + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/EthTypeCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/EthTypeCompleter.java new file mode 100644 index 00000000..b6a2285c --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/EthTypeCompleter.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import java.util.List; +import java.util.SortedSet; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; + +/** + * Ethernet type completer. + */ +public class EthTypeCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + SortedSet<String> strings = delegate.getStrings(); + + for (EthType eth : EthType.values()) { + strings.add(eth.toString()); + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ExtHeader.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ExtHeader.java new file mode 100644 index 00000000..e27332e1 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ExtHeader.java @@ -0,0 +1,87 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +/** + * Known values for IPv6 extension header field that can be supplied to the CLI. + */ +public enum ExtHeader { + /** No next header. */ + NOEXT((short) (1 << 0)), + /** Encapsulated Security Payload. */ + ESP((short) (1 << 1)), + /** Authentication header. */ + AUTH((short) (1 << 2)), + /** Destination header. */ + DEST((short) (1 << 3)), + /** Fragment header. */ + FRAG((short) (1 << 4)), + /** Router header. */ + ROUTE((short) (1 << 5)), + /** Hop-by-hop header. */ + HOP((short) (1 << 6)), + /** Unexpected repeats encountered. */ + UNREP((short) (1 << 7)), + /** Unexpected sequencing encountered. */ + UNSEQ((short) (1 << 8)); + + private short value; + + /** + * Constructs an ExtHeader with the given value. + * + * @param value value to use when this ExtHeader is seen + */ + private ExtHeader(short value) { + this.value = value; + } + + /** + * Gets the value to use for this ExtHeader. + * + * @return short value to use for this ExtHeader + */ + public short value() { + return this.value; + } + + /** + * Parse a string input that could contain an ExtHeader value. The value + * may appear in the string either as a known exntension header name (one of the + * values of this enum), or a numeric extension header value. + * + * @param input the input string to parse + * @return the numeric value of the parsed IPv6 extension header + * @throws IllegalArgumentException if the input string does not contain a + * value that can be parsed into an IPv6 extension header + */ + public static short parseFromString(String input) { + try { + return valueOf(input).value(); + } catch (IllegalArgumentException e) { + // The input is not a known IPv6 extension header name, let's see if + // it's an IPv6 extension header value (short). + // We parse with Short to handle unsigned values correctly. + try { + return Short.parseShort(input); + } catch (NumberFormatException e1) { + throw new IllegalArgumentException( + "ExtHeader value must be either a string extension header name" + + " or an 8-bit extension header value"); + } + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ExtHeaderCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ExtHeaderCompleter.java new file mode 100644 index 00000000..1242e119 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ExtHeaderCompleter.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; + +import java.util.List; +import java.util.SortedSet; + +/** + * IPv6 extension header completer. + */ +public class ExtHeaderCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + SortedSet<String> strings = delegate.getStrings(); + + for (ExtHeader extHeader : ExtHeader.values()) { + strings.add(extHeader.toString()); + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowObjectiveCompositionCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowObjectiveCompositionCommand.java new file mode 100644 index 00000000..9bacc7ae --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowObjectiveCompositionCommand.java @@ -0,0 +1,45 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.flowobjective.FlowObjectiveService; + +/** + * Manages FlowObjectiveComposition policy. + */ +@Command(scope = "onos", name = "policy", + description = "Manages FlowObjectiveComposition policy") +public class FlowObjectiveCompositionCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "command", + description = "Command name (install)", + required = true, multiValued = false) + String command = null; + + @Argument(index = 1, name = "names", description = "policy string", + required = true, multiValued = true) + String[] policies = null; + + @Override + protected void execute() { + FlowObjectiveService service = get(FlowObjectiveService.class); + service.initPolicy(policies[0]); + print("Policy %s installed", policies[0]); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowRuleStatusCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowRuleStatusCompleter.java new file mode 100644 index 00000000..ce910c95 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowRuleStatusCompleter.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import java.util.List; +import java.util.SortedSet; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.net.flow.FlowEntry.FlowEntryState; + +/** + * Flow rule status completer. + */ +public class FlowRuleStatusCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + + FlowEntryState[] states = FlowEntryState.values(); + SortedSet<String> strings = delegate.getStrings(); + for (int i = 0; i < states.length; i++) { + strings.add(states[i].toString().toLowerCase()); + } + strings.add(FlowsListCommand.ANY); + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java new file mode 100644 index 00000000..de84f519 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java @@ -0,0 +1,169 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import static com.google.common.collect.Lists.newArrayList; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cli.Comparators; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.flow.FlowEntry; +import org.onosproject.net.flow.FlowEntry.FlowEntryState; +import org.onosproject.net.flow.FlowRuleService; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Lists all currently-known flows. + */ +@Command(scope = "onos", name = "flows", + description = "Lists all currently-known flows.") +public class FlowsListCommand extends AbstractShellCommand { + + public static final String ANY = "any"; + + private static final String FMT = + " id=%s, state=%s, bytes=%s, packets=%s, duration=%s, priority=%s, tableId=%s appId=%s, payLoad=%s"; + private static final String TFMT = " treatment=%s"; + private static final String SFMT = " selector=%s"; + + @Argument(index = 1, name = "uri", description = "Device ID", + required = false, multiValued = false) + String uri = null; + + @Argument(index = 0, name = "state", description = "Flow Rule state", + required = false, multiValued = false) + String state = null; + + @Override + protected void execute() { + CoreService coreService = get(CoreService.class); + DeviceService deviceService = get(DeviceService.class); + FlowRuleService service = get(FlowRuleService.class); + SortedMap<Device, List<FlowEntry>> flows = getSortedFlows(deviceService, service); + + if (outputJson()) { + print("%s", json(flows.keySet(), flows)); + } else { + flows.forEach((device, flow) -> printFlows(device, flow, coreService)); + } + } + + /** + * Produces a JSON array of flows grouped by the each device. + * + * @param devices collection of devices to group flow by + * @param flows collection of flows per each device + * @return JSON array + */ + private JsonNode json(Iterable<Device> devices, + Map<Device, List<FlowEntry>> flows) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode result = mapper.createArrayNode(); + for (Device device : devices) { + result.add(json(mapper, device, flows.get(device))); + } + return result; + } + + // Produces JSON object with the flows of the given device. + private ObjectNode json(ObjectMapper mapper, + Device device, List<FlowEntry> flows) { + ObjectNode result = mapper.createObjectNode(); + ArrayNode array = mapper.createArrayNode(); + + flows.forEach(flow -> array.add(jsonForEntity(flow, FlowEntry.class))); + + result.put("device", device.id().toString()) + .put("flowCount", flows.size()) + .set("flows", array); + return result; + } + + /** + * Returns the list of devices sorted using the device ID URIs. + * + * @param deviceService device service + * @param service flow rule service + * @return sorted device list + */ + protected SortedMap<Device, List<FlowEntry>> getSortedFlows(DeviceService deviceService, + FlowRuleService service) { + SortedMap<Device, List<FlowEntry>> flows = new TreeMap<>(Comparators.ELEMENT_COMPARATOR); + List<FlowEntry> rules; + FlowEntryState s = null; + if (state != null && !state.equals("any")) { + s = FlowEntryState.valueOf(state.toUpperCase()); + } + Iterable<Device> devices = uri == null ? deviceService.getDevices() : + Collections.singletonList(deviceService.getDevice(DeviceId.deviceId(uri))); + for (Device d : devices) { + if (s == null) { + rules = newArrayList(service.getFlowEntries(d.id())); + } else { + rules = newArrayList(); + for (FlowEntry f : service.getFlowEntries(d.id())) { + if (f.state().equals(s)) { + rules.add(f); + } + } + } + rules.sort(Comparators.FLOW_RULE_COMPARATOR); + flows.put(d, rules); + } + return flows; + } + + /** + * Prints flows. + * + * @param d the device + * @param flows the set of flows for that device + * @param coreService core system service + */ + 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()); + if (!empty) { + for (FlowEntry f : flows) { + ApplicationId appId = coreService.getAppId(f.appId()); + print(FMT, Long.toHexString(f.id().value()), f.state(), + f.bytes(), f.packets(), f.life(), f.priority(), f.tableId(), + appId != null ? appId.name() : "<none>", + f.payLoad() == null ? null : f.payLoad().payLoad().toString()); + print(SFMT, f.selector().criteria()); + print(TFMT, f.treatment()); + } + } + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GetStatistics.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GetStatistics.java new file mode 100644 index 00000000..911e03c2 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GetStatistics.java @@ -0,0 +1,85 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; + +import org.onosproject.net.statistic.Load; +import org.onosproject.net.statistic.StatisticService; + + +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Fetches statistics. + */ +@Command(scope = "onos", name = "get-stats", + description = "Fetches stats for a connection point") +public class GetStatistics extends AbstractShellCommand { + + @Argument(index = 0, name = "connectPoint", + description = "Device/Port Description", + required = true, multiValued = false) + String connectPoint = null; + + + @Override + protected void execute() { + StatisticService service = get(StatisticService.class); + + DeviceId ingressDeviceId = deviceId(getDeviceId(connectPoint)); + PortNumber ingressPortNumber = portNumber(getPortNumber(connectPoint)); + ConnectPoint cp = new ConnectPoint(ingressDeviceId, ingressPortNumber); + + Load load = service.load(cp); + + print("Load on %s -> %s", cp, load); + } + + /** + * Extracts the port number portion of the ConnectPoint. + * + * @param deviceString string representing the device/port + * @return port number as a string, empty string if the port is not found + */ + private String getPortNumber(String deviceString) { + int slash = deviceString.indexOf('/'); + if (slash <= 0) { + return ""; + } + return deviceString.substring(slash + 1, deviceString.length()); + } + + /** + * Extracts the device ID portion of the ConnectPoint. + * + * @param deviceString string representing the device/port + * @return device ID string + */ + private String getDeviceId(String deviceString) { + int slash = deviceString.indexOf('/'); + if (slash <= 0) { + return ""; + } + return deviceString.substring(0, slash); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GlobalLabelApplyCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GlobalLabelApplyCommand.java new file mode 100644 index 00000000..a8e8f2e0 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GlobalLabelApplyCommand.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import java.util.Collection; +import java.util.Iterator; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.incubator.net.resource.label.DefaultLabelResource; +import org.onosproject.incubator.net.resource.label.LabelResource; +import org.onosproject.incubator.net.resource.label.LabelResourceService; + +@Command(scope = "onos", name = "global-label-apply", + description = "Apply global labels from global resource pool") +public class GlobalLabelApplyCommand extends AbstractShellCommand { + @Argument(index = 0, name = "applyNum", + description = "Applying number means how many labels applications want to use.", + required = true, multiValued = false) + String applyNum = null; + + private static final String FMT = "deviceid=%s, labelresourceid=%s"; + + @Override + protected void execute() { + LabelResourceService lrs = get(LabelResourceService.class); + Collection<LabelResource> result = + lrs.applyFromGlobalPool(Long.parseLong(applyNum)); + if (result.size() > 0) { + for (Iterator<LabelResource> iterator = result.iterator(); iterator + .hasNext();) { + DefaultLabelResource defaultLabelResource = (DefaultLabelResource) iterator + .next(); + print(FMT, defaultLabelResource.deviceId().toString(), + defaultLabelResource.labelResourceId().toString()); + } + } + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GlobalLabelCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GlobalLabelCommand.java new file mode 100644 index 00000000..92f39ccd --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GlobalLabelCommand.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.incubator.net.resource.label.LabelResourcePool; +import org.onosproject.incubator.net.resource.label.LabelResourceService; + +@Command(scope = "onos", name = "global-label-pool", + description = "Gets global label resource pool information.") +public class GlobalLabelCommand extends AbstractShellCommand { + private static final String FMT = "deviceid=%s, beginLabel=%s," + + "endLabel=%s, totalNum=%s, usedNum=%s, currentUsedMaxLabelId=%s," + + "releaseLabelIds=%s"; + + @Override + protected void execute() { + LabelResourceService lrs = get(LabelResourceService.class); + LabelResourcePool pool = lrs.getGlobalLabelResourcePool(); + if (pool != null) { + print(FMT, pool.deviceId().toString(), pool.beginLabel(), + pool.endLabel(), pool.totalNum(), pool.usedNum(), + pool.currentUsedMaxLabelId(), pool.releaseLabelId() + .toString()); + } + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GlobalLabelPoolCreateCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GlobalLabelPoolCreateCommand.java new file mode 100644 index 00000000..3e226678 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GlobalLabelPoolCreateCommand.java @@ -0,0 +1,47 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.incubator.net.resource.label.LabelResourceAdminService; +import org.onosproject.incubator.net.resource.label.LabelResourceId; + +/** + * create label resource pool by specific device id. + */ +@Command(scope = "onos", name = "global-label-pool-create", +description = "Creates global label resource pool.") +public class GlobalLabelPoolCreateCommand extends AbstractShellCommand { + @Argument(index = 0, name = "beginLabel", + description = "The first label of global label resource pool.", + required = true, multiValued = false) + String beginLabel = null; + @Argument(index = 1, name = "endLabel", + description = "The last label of global label resource pool.", + required = true, multiValued = false) + String endLabel = null; + + @Override + protected void execute() { + LabelResourceAdminService lrs = get(LabelResourceAdminService.class); + lrs.createGlobalPool(LabelResourceId.labelResourceId(Long + .parseLong(beginLabel)), LabelResourceId.labelResourceId(Long + .parseLong(endLabel))); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GlobalLabelPoolDestoryCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GlobalLabelPoolDestoryCommand.java new file mode 100644 index 00000000..ae1bee64 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GlobalLabelPoolDestoryCommand.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.incubator.net.resource.label.LabelResourceAdminService; + +@Command(scope = "onos", name = "global-label-pool-destroy", +description = "Destroys global label resource pool") +public class GlobalLabelPoolDestoryCommand extends AbstractShellCommand { + @Override + protected void execute() { + LabelResourceAdminService lrs = get(LabelResourceAdminService.class); + lrs.destroyGlobalPool(); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GlobalLabelReleaseCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GlobalLabelReleaseCommand.java new file mode 100644 index 00000000..737f7961 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GlobalLabelReleaseCommand.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.incubator.net.resource.label.LabelResourceId; +import org.onosproject.incubator.net.resource.label.LabelResourceService; + +@Command(scope = "onos", name = "global-label-release", +description = "Releases labels to global label resource pool.") +public class GlobalLabelReleaseCommand extends AbstractShellCommand { + @Argument(index = 0, name = "releaseLabelIds", + description = "Represents for the label ids that are released. They are splited by dot symbol", + required = true, multiValued = false) + String releaseLabelIds = null; + + @Override + protected void execute() { + LabelResourceService lrs = get(LabelResourceService.class); + Set<LabelResourceId> release = new HashSet<LabelResourceId>(); + String[] labelIds = releaseLabelIds.split(","); + LabelResourceId resource = null; + for (int i = 0; i < labelIds.length; i++) { + resource = LabelResourceId.labelResourceId(Long.parseLong(labelIds[i])); + release.add(resource); + } + lrs.releaseToGlobalPool(release); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java new file mode 100644 index 00000000..afbcab80 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/GroupsListCommand.java @@ -0,0 +1,134 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cli.Comparators; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.group.Group; +import org.onosproject.net.group.Group.GroupState; +import org.onosproject.net.group.GroupBucket; +import org.onosproject.net.group.GroupService; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; + +import static com.google.common.collect.Lists.newArrayList; + +/** + * Lists all groups in the system. + */ +@Command(scope = "onos", name = "groups", + description = "Lists all groups in the system") +public class GroupsListCommand extends AbstractShellCommand { + + private static final String FORMAT = + " id=%s, state=%s, bytes=%s, packets=%s, appId=%s"; + private static final String BUCKET_FORMAT = + " id=%s, bucket=%s, bytes=%s, packets=%s, actions=%s"; + + @Argument(index = 1, name = "uri", description = "Device ID", + required = false, multiValued = false) + String uri = null; + + @Argument(index = 0, name = "state", description = "Group state", + required = false, multiValued = false) + String state; + + private JsonNode json(Map<Device, List<Group>> sortedGroups) { + ArrayNode result = mapper().createArrayNode(); + + sortedGroups.forEach((device, groups) -> + groups.forEach(group -> + result.add(jsonForEntity(group, Group.class)))); + + return result; + } + + @Override + protected void execute() { + DeviceService deviceService = get(DeviceService.class); + GroupService groupService = get(GroupService.class); + SortedMap<Device, List<Group>> sortedGroups = + getSortedGroups(deviceService, groupService); + + if (outputJson()) { + print("%s", json(sortedGroups)); + } else { + sortedGroups.forEach((device, groups) -> printGroups(device.id(), groups)); + } + } + + /** + * Returns the list of devices sorted using the device ID URIs. + * + * @param deviceService device service + * @param groupService group service + * @return sorted device list + */ + protected SortedMap<Device, List<Group>> + getSortedGroups(DeviceService deviceService, + GroupService groupService) { + SortedMap<Device, List<Group>> sortedGroups = + new TreeMap<>(Comparators.ELEMENT_COMPARATOR); + List<Group> groups; + GroupState s = null; + if (state != null && !state.equals("any")) { + s = GroupState.valueOf(state.toUpperCase()); + } + Iterable<Device> devices = (uri == null) ? deviceService.getDevices() : + Collections.singletonList(deviceService.getDevice(DeviceId.deviceId(uri))); + for (Device d : devices) { + if (s == null) { + groups = newArrayList(groupService.getGroups(d.id())); + } else { + groups = newArrayList(); + for (Group g : groupService.getGroups(d.id())) { + if (g.state().equals(s)) { + groups.add(g); + } + } + } + groups.sort(Comparators.GROUP_COMPARATOR); + sortedGroups.put(d, groups); + } + return sortedGroups; + } + + private void printGroups(DeviceId deviceId, List<Group> groups) { + print("deviceId=%s", deviceId); + for (Group group : groups) { + print(FORMAT, group.id().id(), group.state(), + group.bytes(), group.packets(), group.appId().name()); + int i = 0; + for (GroupBucket bucket:group.buckets().buckets()) { + print(BUCKET_FORMAT, group.id().id(), ++i, + bucket.bytes(), bucket.packets(), + bucket.treatment().allInstructions()); + } + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/HostIdCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/HostIdCompleter.java new file mode 100644 index 00000000..4694425f --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/HostIdCompleter.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.Host; +import org.onosproject.net.host.HostService; + +/** + * Host ID completer. + */ +public class HostIdCompleter implements Completer { + + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + + HostService service = AbstractShellCommand.get(HostService.class); + Iterator<Host> it = service.getHosts().iterator(); + SortedSet<String> strings = delegate.getStrings(); + while (it.hasNext()) { + strings.add(it.next().id().toString()); + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/HostRemoveCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/HostRemoveCommand.java new file mode 100644 index 00000000..c0db07db --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/HostRemoveCommand.java @@ -0,0 +1,40 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.HostId; +import org.onosproject.net.host.HostAdminService; + +/** + * Removes an end-station host. + */ +@Command(scope = "onos", name = "host-remove", + description = "Removes an end-station host") +public class HostRemoveCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "id", description = "Host ID", + required = true, multiValued = false) + String id = null; + + @Override + protected void execute() { + get(HostAdminService.class).removeHost(HostId.hostId(id)); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/HostsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/HostsListCommand.java new file mode 100644 index 00000000..a90627e4 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/HostsListCommand.java @@ -0,0 +1,90 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import java.util.Collections; +import java.util.List; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cli.Comparators; +import org.onosproject.net.Host; +import org.onosproject.net.host.HostService; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; + +import static com.google.common.collect.Lists.newArrayList; + +/** + * Lists all currently-known hosts. + */ +@Command(scope = "onos", name = "hosts", + description = "Lists all currently-known hosts.") +public class HostsListCommand extends AbstractShellCommand { + + private static final String FMT = + "id=%s, mac=%s, location=%s/%s, vlan=%s, ip(s)=%s%s"; + + @Override + protected void execute() { + HostService service = get(HostService.class); + if (outputJson()) { + print("%s", json(getSortedHosts(service))); + } else { + for (Host host : getSortedHosts(service)) { + printHost(host); + } + } + } + + // Produces JSON structure. + private JsonNode json(Iterable<Host> hosts) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode result = mapper.createArrayNode(); + + hosts.forEach(host -> result.add(jsonForEntity(host, Host.class))); + return result; + } + + /** + * Returns the list of devices sorted using the device ID URIs. + * + * @param service device service + * @return sorted device list + */ + protected List<Host> getSortedHosts(HostService service) { + List<Host> hosts = newArrayList(service.getHosts()); + Collections.sort(hosts, Comparators.ELEMENT_COMPARATOR); + return hosts; + } + + /** + * Prints information about a host. + * + * @param host end-station host + */ + protected void printHost(Host host) { + if (host != null) { + print(FMT, host.id(), host.mac(), + host.location().deviceId(), + host.location().port(), + host.vlan(), host.ipAddresses(), + annotations(host.annotations())); + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/Icmp6Code.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/Icmp6Code.java new file mode 100644 index 00000000..8568ec62 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/Icmp6Code.java @@ -0,0 +1,102 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.onlab.packet.ICMP6; + +/** + * Known values for ICMPv6 code field that can be supplied to the CLI. + */ +public enum Icmp6Code { + // Code for DEST_UNREACH + /** No route to destination. */ + NO_ROUTE(ICMP6.NO_ROUTE), + /** Communication with destination administratively prohibited. */ + COMM_PROHIBIT(ICMP6.COMM_PROHIBIT), + /** Beyond scope of source address. */ + BEYOND_SCOPE(ICMP6.BEYOND_SCOPE), + /** Address unreachable. */ + ADDR_UNREACH(ICMP6.ADDR_UNREACH), + /** Port unreachable. */ + PORT_UNREACH(ICMP6.PORT_UNREACH), + /** Source address failed ingress/egress policy. */ + FAIL_POLICY(ICMP6.FAIL_POLICY), + /** Reject route to destination. */ + REJECT_ROUTE(ICMP6.REJECT_ROUTE), + /** Error in Source Routing Header. */ + SRC_ROUTING_HEADER_ERR(ICMP6.SRC_ROUTING_HEADER_ERR), + + // Code for TIME_EXCEED + /** Hop limit exceeded in transit. */ + HOP_LIMIT_EXCEED(ICMP6.HOP_LIMIT_EXCEED), + /** Fragment reassembly time exceeded. */ + DEFRAG_TIME_EXCEED(ICMP6.DEFRAG_TIME_EXCEED), + + // Code for PARAM_ERR + /** Erroneous header field encountered. */ + HDR_FIELD_ERR(ICMP6.HDR_FIELD_ERR), + /** Unrecognized Next Header type encountered. */ + NEXT_HEADER_ERR(ICMP6.NEXT_HEADER_ERR), + /** Unrecognized IPv6 option encountered. */ + IPV6_OPT_ERR(ICMP6.IPV6_OPT_ERR); + + private byte value; + + /** + * Constructs an Icmp6Code with the given value. + * + * @param value value to use when this Icmp6Code is seen + */ + private Icmp6Code(byte value) { + this.value = value; + } + + /** + * Gets the value to use for this Icmp6Code. + * + * @return short value to use for this Icmp6Code + */ + public byte value() { + return this.value; + } + + /** + * Parse a string input that could contain an Icmp6Code value. The value + * may appear in the string either as a known code name (one of the + * values of this enum), or a numeric code value. + * + * @param input the input string to parse + * @return the numeric value of the parsed ICMPv6 code + * @throws IllegalArgumentException if the input string does not contain a + * value that can be parsed into an ICMPv6 code + */ + public static byte parseFromString(String input) { + try { + return valueOf(input).value(); + } catch (IllegalArgumentException e) { + // The input is not a known ICMPv6 code name, let's see if it's an ICMP6 + // code value (byte). We parse with Byte to handle unsigned values + // correctly. + try { + return Byte.parseByte(input); + } catch (NumberFormatException e1) { + throw new IllegalArgumentException( + "Icmp6Code value must be either a string code name" + + " or an 8-bit code value"); + } + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/Icmp6CodeCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/Icmp6CodeCompleter.java new file mode 100644 index 00000000..bf32d4f8 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/Icmp6CodeCompleter.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; + +import java.util.List; +import java.util.SortedSet; + +/** + * ICMPv6 type completer. + */ +public class Icmp6CodeCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + SortedSet<String> strings = delegate.getStrings(); + + for (Icmp6Code code : Icmp6Code.values()) { + strings.add(code.toString()); + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/Icmp6Type.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/Icmp6Type.java new file mode 100644 index 00000000..a9bffd0a --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/Icmp6Type.java @@ -0,0 +1,100 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.onlab.packet.ICMP6; + +/** + * Known values for ICMPv6 type field that can be supplied to the CLI. + */ +public enum Icmp6Type { + /** Destination Unreachable. */ + DEST_UNREACH(ICMP6.DEST_UNREACH), + /** Packet Too Big. */ + PKT_TOO_BIG(ICMP6.PKT_TOO_BIG), + /** Time Exceeded. */ + TIME_EXCEED(ICMP6.TIME_EXCEED), + /** Parameter Problem. */ + PARAM_ERR(ICMP6.PARAM_ERR), + /** Echo Request. */ + ECHO_REQUEST(ICMP6.ECHO_REQUEST), + /** Echo Reply. */ + ECHO_REPLY(ICMP6.ECHO_REPLY), + /** Multicast Listener Query. */ + MCAST_QUERY(ICMP6.MCAST_QUERY), + /** Multicast Listener Report. */ + MCAST_REPORT(ICMP6.MCAST_REPORT), + /** Multicast Listener Done. */ + MCAST_DONE(ICMP6.MCAST_DONE), + /** Router Solicitation. */ + ROUTER_SOLICITATION(ICMP6.ROUTER_SOLICITATION), + /** Router Advertisement. */ + ROUTER_ADVERTISEMENT(ICMP6.ROUTER_ADVERTISEMENT), + /** Neighbor Solicitation. */ + NEIGHBOR_SOLICITATION(ICMP6.NEIGHBOR_SOLICITATION), + /** Neighbor Advertisement. */ + NEIGHBOR_ADVERTISEMENT(ICMP6.NEIGHBOR_ADVERTISEMENT), + /** Redirect Message. */ + REDIRECT(ICMP6.REDIRECT); + + + private byte value; + + /** + * Constructs an Icmp6Type with the given value. + * + * @param value value to use when this Icmp6Type is seen + */ + private Icmp6Type(byte value) { + this.value = value; + } + + /** + * Gets the value to use for this Icmp6Type. + * + * @return short value to use for this Icmp6Type + */ + public byte value() { + return this.value; + } + + /** + * Parse a string input that could contain an Icmp6Type value. The value + * may appear in the string either as a known type name (one of the + * values of this enum), or a numeric type value. + * + * @param input the input string to parse + * @return the numeric value of the parsed ICMPv6 type + * @throws IllegalArgumentException if the input string does not contain a + * value that can be parsed into an ICMPv6 type + */ + public static byte parseFromString(String input) { + try { + return valueOf(input).value(); + } catch (IllegalArgumentException e) { + // The input is not a known ICMPv6 type name, let's see if it's an ICMP6 + // type value (byte). We parse with Byte to handle unsigned values + // correctly. + try { + return Byte.parseByte(input); + } catch (NumberFormatException e1) { + throw new IllegalArgumentException( + "Icmp6Type value must be either a string type name" + + " or an 8-bit type value"); + } + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/Icmp6TypeCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/Icmp6TypeCompleter.java new file mode 100644 index 00000000..8871388e --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/Icmp6TypeCompleter.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; + +import java.util.List; +import java.util.SortedSet; + +/** + * ICMPv6 type completer. + */ +public class Icmp6TypeCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + SortedSet<String> strings = delegate.getStrings(); + + for (Icmp6Type type : Icmp6Type.values()) { + strings.add(type.toString()); + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentCycleCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentCycleCommand.java new file mode 100644 index 00000000..1c01c5ba --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentCycleCommand.java @@ -0,0 +1,206 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import java.util.EnumSet; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onlab.packet.Ethernet; +import org.onlab.packet.MacAddress; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentEvent; +import org.onosproject.net.intent.IntentEvent.Type; +import org.onosproject.net.intent.IntentListener; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.Key; +import org.onosproject.net.intent.PointToPointIntent; + +import com.google.common.collect.Lists; + +import static org.onlab.util.Tools.delay; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Installs point-to-point connectivity intents. + */ +@Command(scope = "onos", name = "cycle-intents", + description = "Installs random intents to test throughput") +public class IntentCycleCommand extends AbstractShellCommand + implements IntentListener { + + @Argument(index = 0, name = "ingressDevice", + description = "Ingress Device/Port Description", + required = true, multiValued = false) + String ingressDeviceString = null; + + @Argument(index = 1, name = "egressDevice", + description = "Egress Device/Port Description", + required = true, multiValued = false) + String egressDeviceString = null; + + @Argument(index = 2, name = "numberOfIntents", + description = "Number of intents to install/withdraw", + required = true, multiValued = false) + String numberOfIntents = null; + + @Argument(index = 3, name = "keyOffset", + description = "Starting point for first key (default: 1)", + required = false, multiValued = false) + String keyOffsetStr = null; + + private IntentService service; + private CountDownLatch latch; + private volatile long start, end; + private int count; + private int keyOffset; + private long submitCounter = 0; + private AtomicLong eventCounter = new AtomicLong(0); + private boolean add; + + @Override + protected void execute() { + service = get(IntentService.class); + + + DeviceId ingressDeviceId = deviceId(getDeviceId(ingressDeviceString)); + PortNumber ingressPortNumber = portNumber(getPortNumber(ingressDeviceString)); + ConnectPoint ingress = new ConnectPoint(ingressDeviceId, ingressPortNumber); + + DeviceId egressDeviceId = deviceId(getDeviceId(egressDeviceString)); + PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString)); + ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber); + + count = Integer.parseInt(numberOfIntents); + keyOffset = (keyOffsetStr != null) ? Integer.parseInt(keyOffsetStr) : 1; + + service.addListener(this); + + List<Intent> operations = generateIntents(ingress, egress); + + add = true; + start = System.currentTimeMillis(); + while (start + 10000 > System.currentTimeMillis()) { + submitIntents(operations); + } + delay(5000); + printResults(); + + add = false; + submitIntents(operations); + + service.removeListener(this); + } + + private List<Intent> generateIntents(ConnectPoint ingress, ConnectPoint egress) { + TrafficSelector.Builder selectorBldr = DefaultTrafficSelector.builder() + .matchEthType(Ethernet.TYPE_IPV4); + TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); + + List<Intent> intents = Lists.newArrayList(); + for (int i = 0; i < count; i++) { + TrafficSelector selector = selectorBldr + .matchEthSrc(MacAddress.valueOf(i + keyOffset)) + .build(); + intents.add( + PointToPointIntent.builder() + .appId(appId()) + .key(Key.of(i + keyOffset, appId())) + .selector(selector) + .treatment(treatment) + .ingressPoint(ingress) + .egressPoint(egress) + .build()); + + + } + return intents; + } + + private void submitIntents(List<Intent> intents) { + for (Intent intent : intents) { + if (add) { + submitCounter++; + service.submit(intent); + } else { + service.withdraw(intent); + } + } + } + + private void printResults() { + //long delta = end - start; + //String text = add ? "install" : "withdraw"; + print("count: %s / %s", eventCounter, Long.valueOf(submitCounter)); + //print("Time to %s %d intents: %d ms", text, count, delta); + } + + /** + * Extracts the port number portion of the ConnectPoint. + * + * @param deviceString string representing the device/port + * @return port number as a string, empty string if the port is not found + */ + private String getPortNumber(String deviceString) { + int slash = deviceString.indexOf('/'); + if (slash <= 0) { + return ""; + } + return deviceString.substring(slash + 1, deviceString.length()); + } + + /** + * Extracts the device ID portion of the ConnectPoint. + * + * @param deviceString string representing the device/port + * @return device ID string + */ + private String getDeviceId(String deviceString) { + int slash = deviceString.indexOf('/'); + if (slash <= 0) { + return ""; + } + return deviceString.substring(0, slash); + } + + private static final EnumSet<Type> IGNORE_EVENT + = EnumSet.of(Type.INSTALL_REQ, Type.WITHDRAW_REQ); + @Override + public synchronized void event(IntentEvent event) { + if (!appId().equals(event.subject().appId())) { + // not my event, ignore + return; + } + Type expected = add ? Type.INSTALLED : Type.WITHDRAWN; + if (event.type() == expected) { + eventCounter.getAndIncrement(); + } else if (IGNORE_EVENT.contains(event.type())) { + log.info("Unexpected intent event: {}", event); + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentKeyCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentKeyCompleter.java new file mode 100644 index 00000000..e3f647b4 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentKeyCompleter.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentService; + +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; + +/** + * Intent Key completer. + */ +public class IntentKeyCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + + // Fetch our service and feed it's offerings to the string completer + IntentService service = AbstractShellCommand.get(IntentService.class); + Iterator<Intent> it = service.getIntents().iterator(); + SortedSet<String> strings = delegate.getStrings(); + while (it.hasNext()) { + strings.add(it.next().key().toString()); + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentPurgeCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentPurgeCommand.java new file mode 100644 index 00000000..61174e70 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentPurgeCommand.java @@ -0,0 +1,40 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentService; + +import static org.onosproject.net.intent.IntentState.WITHDRAWN; + +/** + * Purges all WITHDRAWN intents. + */ +@Command(scope = "onos", name = "purge-intents", + description = "Purges all WITHDRAWN intents") +public class IntentPurgeCommand extends AbstractShellCommand { + @Override + protected void execute() { + IntentService intentService = get(IntentService.class); + for (Intent intent: intentService.getIntents()) { + if (intentService.getIntentState(intent.key()) == WITHDRAWN) { + intentService.purge(intent); + } + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentPushTestCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentPushTestCommand.java new file mode 100644 index 00000000..15921fed --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentPushTestCommand.java @@ -0,0 +1,232 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import java.util.EnumSet; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onlab.packet.Ethernet; +import org.onlab.packet.MacAddress; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentEvent; +import org.onosproject.net.intent.IntentEvent.Type; +import org.onosproject.net.intent.IntentListener; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.Key; +import org.onosproject.net.intent.PointToPointIntent; + +import com.google.common.collect.Lists; + +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Installs bulk point-to-point connectivity intents between given ingress/egress devices. + */ +@Command(scope = "onos", name = "push-test-intents", + description = "Installs random intents to test throughput") +public class IntentPushTestCommand extends AbstractShellCommand + implements IntentListener { + + @Argument(index = 0, name = "ingressDevice", + description = "Ingress Device/Port Description", + required = true, multiValued = false) + String ingressDeviceString = null; + + @Argument(index = 1, name = "egressDevice", + description = "Egress Device/Port Description", + required = true, multiValued = false) + String egressDeviceString = null; + + @Argument(index = 2, name = "numberOfIntents", + description = "Number of intents to install/withdraw", + required = true, multiValued = false) + String numberOfIntents = null; + + @Argument(index = 3, name = "keyOffset", + description = "Starting point for first key (default: 1)", + required = false, multiValued = false) + String keyOffsetStr = null; + + @Option(name = "-i", aliases = "--install", + description = "Install intents", + required = false, multiValued = false) + private boolean installOnly = false; + + @Option(name = "-w", aliases = "--withdraw", + description = "Withdraw intents", + required = false, multiValued = false) + private boolean withdrawOnly = false; + + private IntentService service; + private CountDownLatch latch; + private volatile long start, end; + private int count; + private int keyOffset; + private boolean add; + + @Override + protected void execute() { + service = get(IntentService.class); + + + DeviceId ingressDeviceId = deviceId(getDeviceId(ingressDeviceString)); + PortNumber ingressPortNumber = portNumber(getPortNumber(ingressDeviceString)); + ConnectPoint ingress = new ConnectPoint(ingressDeviceId, ingressPortNumber); + + DeviceId egressDeviceId = deviceId(getDeviceId(egressDeviceString)); + PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString)); + ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber); + + count = Integer.parseInt(numberOfIntents); + keyOffset = (keyOffsetStr != null) ? Integer.parseInt(keyOffsetStr) : 1; + + service.addListener(this); + + List<Intent> operations = generateIntents(ingress, egress); + + boolean both = !(installOnly ^ withdrawOnly); + + if (installOnly || both) { + add = true; + submitIntents(operations); + } + + if (withdrawOnly || both) { + add = false; + submitIntents(operations); + } + + service.removeListener(this); + } + + private List<Intent> generateIntents(ConnectPoint ingress, ConnectPoint egress) { + TrafficSelector.Builder selectorBldr = DefaultTrafficSelector.builder() + .matchEthType(Ethernet.TYPE_IPV4); + TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); + + List<Intent> intents = Lists.newArrayList(); + for (int i = 0; i < count; i++) { + TrafficSelector selector = selectorBldr + .matchEthSrc(MacAddress.valueOf(i + keyOffset)) + .build(); + intents.add(PointToPointIntent.builder() + .appId(appId()) + .key(Key.of(i + keyOffset, appId())) + .selector(selector) + .treatment(treatment) + .ingressPoint(ingress) + .egressPoint(egress) + .build()); + + + } + return intents; + } + + private void submitIntents(List<Intent> intents) { + latch = new CountDownLatch(count); + start = System.currentTimeMillis(); + for (Intent intent : intents) { + if (add) { + service.submit(intent); + } else { + service.withdraw(intent); + } + } + + try { + if (latch.await(500 + count * 30, TimeUnit.MILLISECONDS)) { + printResults(count); + } else { + print("Failure: %d intents not installed", latch.getCount()); + } + } catch (InterruptedException e) { + print(e.toString()); + } + } + + private void printResults(int count) { + long delta = end - start; + String text = add ? "install" : "withdraw"; + print("Time to %s %d intents: %d ms", text, count, delta); + } + + /** + * Extracts the port number portion of the ConnectPoint. + * + * @param deviceString string representing the device/port + * @return port number as a string, empty string if the port is not found + */ + private String getPortNumber(String deviceString) { + int slash = deviceString.indexOf('/'); + if (slash <= 0) { + return ""; + } + return deviceString.substring(slash + 1, deviceString.length()); + } + + /** + * Extracts the device ID portion of the ConnectPoint. + * + * @param deviceString string representing the device/port + * @return device ID string + */ + private String getDeviceId(String deviceString) { + int slash = deviceString.indexOf('/'); + if (slash <= 0) { + return ""; + } + return deviceString.substring(0, slash); + } + + private static final EnumSet<IntentEvent.Type> IGNORE_EVENT + = EnumSet.of(Type.INSTALL_REQ, Type.WITHDRAW_REQ); + @Override + public synchronized void event(IntentEvent event) { + if (!appId().equals(event.subject().appId())) { + // not my event, ignore + return; + } + Type expected = add ? Type.INSTALLED : Type.WITHDRAWN; + if (event.type() == expected) { + end = Math.max(end, event.time()); + if (latch != null) { + if (latch.getCount() == 0) { + log.warn("Latch was already 0 before counting down?"); + } + latch.countDown(); + } else { + log.warn("install event latch is null"); + } + } else if (IGNORE_EVENT.contains(event.type())) { + log.debug("Unexpected intent event: {}", event); + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentRemoveCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentRemoveCommand.java new file mode 100644 index 00000000..492b3a27 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentRemoveCommand.java @@ -0,0 +1,170 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentState; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.IntentListener; +import org.onosproject.net.intent.IntentEvent; +import org.onosproject.net.intent.Key; + +import java.math.BigInteger; +import java.util.EnumSet; +import java.util.Objects; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static org.onosproject.net.intent.IntentState.FAILED; +import static org.onosproject.net.intent.IntentState.WITHDRAWN; + +/** + * Removes an intent. + */ +@Command(scope = "onos", name = "remove-intent", + description = "Removes the specified intent") +public class IntentRemoveCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "app", + description = "Application ID", + required = false, multiValued = false) + String applicationIdString = null; + + @Argument(index = 1, name = "key", + description = "Intent Key", + required = false, multiValued = false) + String keyString = null; + + @Option(name = "-p", aliases = "--purge", + description = "Purge the intent from the store after removal", + required = false, multiValued = false) + private boolean purgeAfterRemove = false; + + @Option(name = "-s", aliases = "--sync", + description = "Waits for the removal before returning", + required = false, multiValued = false) + private boolean sync = false; + + private static final EnumSet<IntentState> CAN_PURGE = EnumSet.of(WITHDRAWN, FAILED); + + @Override + protected void execute() { + IntentService intentService = get(IntentService.class); + CoreService coreService = get(CoreService.class); + + if (purgeAfterRemove || sync) { + print("Using \"sync\" to remove/purge intents - this may take a while..."); + print("Check \"summary\" to see remove/purge progress."); + } + + ApplicationId appId = appId(); + if (!isNullOrEmpty(applicationIdString)) { + appId = coreService.getAppId(applicationIdString); + if (appId == null) { + print("Cannot find application Id %s", applicationIdString); + return; + } + } + + if (isNullOrEmpty(keyString)) { + for (Intent intent : intentService.getIntents()) { + if (intent.appId().equals(appId)) { + removeIntent(intentService, intent); + } + } + + } else { + final Key key; + if (keyString.startsWith("0x")) { + // The intent uses a LongKey + keyString = keyString.replaceFirst("0x", ""); + key = Key.of(new BigInteger(keyString, 16).longValue(), appId); + } else { + // The intent uses a StringKey + key = Key.of(keyString, appId); + } + + Intent intent = intentService.getIntent(key); + if (intent != null) { + removeIntent(intentService, intent); + } + } + } + + private void removeIntent(IntentService intentService, Intent intent) { + IntentListener listener = null; + Key key = intent.key(); + final CountDownLatch withdrawLatch, purgeLatch; + if (purgeAfterRemove || sync) { + // set up latch and listener to track uninstall progress + withdrawLatch = new CountDownLatch(1); + purgeLatch = purgeAfterRemove ? new CountDownLatch(1) : null; + listener = (IntentEvent event) -> { + if (Objects.equals(event.subject().key(), key)) { + if (event.type() == IntentEvent.Type.WITHDRAWN || + event.type() == IntentEvent.Type.FAILED) { + withdrawLatch.countDown(); + } else if (purgeAfterRemove && + event.type() == IntentEvent.Type.PURGED) { + purgeLatch.countDown(); + } + } + }; + intentService.addListener(listener); + } else { + purgeLatch = null; + withdrawLatch = null; + } + + // request the withdraw + intentService.withdraw(intent); + + if (purgeAfterRemove || sync) { + try { // wait for withdraw event + withdrawLatch.await(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + print("Timed out waiting for intent {} withdraw", key); + } + if (purgeAfterRemove && CAN_PURGE.contains(intentService.getIntentState(key))) { + intentService.purge(intent); + if (sync) { // wait for purge event + /* TODO + Technically, the event comes before map.remove() is called. + If we depend on sync and purge working together, we will + need to address this. + */ + try { + purgeLatch.await(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + print("Timed out waiting for intent {} purge", key); + } + } + } + } + + if (listener != null) { + // clean up the listener + intentService.removeListener(listener); + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentsListCommand.java new file mode 100644 index 00000000..55b9ec9c --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IntentsListCommand.java @@ -0,0 +1,398 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import java.util.List; + +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.intent.ConnectivityIntent; +import org.onosproject.net.intent.HostToHostIntent; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.IntentState; +import org.onosproject.net.intent.LinkCollectionIntent; +import org.onosproject.net.intent.MultiPointToSinglePointIntent; +import org.onosproject.net.intent.PathIntent; +import org.onosproject.net.intent.PointToPointIntent; +import org.onosproject.net.intent.SinglePointToMultiPointIntent; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Lists the inventory of intents and their states. + */ +@Command(scope = "onos", name = "intents", + description = "Lists the inventory of intents and their states") +public class IntentsListCommand extends AbstractShellCommand { + + @Option(name = "-i", aliases = "--installable", + description = "Output Installable Intents", + required = false, multiValued = false) + private boolean showInstallable = false; + + @Option(name = "-s", aliases = "--summary", + description = "Intents summary", + required = false, multiValued = false) + private boolean intentsSummary = false; + + @Option(name = "-p", aliases = "--pending", + description = "Show inforamtion about pending intents", + required = false, multiValued = false) + private boolean pending = false; + + @Override + protected void execute() { + IntentService service = get(IntentService.class); + + if (intentsSummary) { + IntentSummaries intentSummaries = new IntentSummaries(); + intentSummaries.collectIntentSummary(service, + service.getIntents()); + if (outputJson()) { + print("%s", intentSummaries.json()); + } else { + intentSummaries.printSummary(); + } + return; + } else if (pending) { + 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()) + ); + } + return; + } + + 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); + } + } + } + } + + /** + * Internal local class to keep track of all intent summaries. + */ + private class IntentSummaries { + private IntentSummary summaryAll; + private IntentSummary summaryConnectivity; + private IntentSummary summaryHostToHost; + private IntentSummary summaryPointToPoint; + private IntentSummary summaryMultiPointToSinglePoint; + private IntentSummary summarySinglePointToMultiPoint; + private IntentSummary summaryPath; + private IntentSummary summaryLinkCollection; + private IntentSummary summaryUnknownType; + + /** + * Initializes the internal state. + */ + private void init() { + summaryAll = new IntentSummary("All"); + summaryConnectivity = new IntentSummary("Connectivity"); + summaryHostToHost = new IntentSummary("HostToHost"); + summaryPointToPoint = new IntentSummary("PointToPoint"); + summaryMultiPointToSinglePoint = + new IntentSummary("MultiPointToSinglePoint"); + summarySinglePointToMultiPoint = + new IntentSummary("SinglePointToMultiPoint"); + summaryPath = new IntentSummary("Path"); + summaryLinkCollection = new IntentSummary("LinkCollection"); + summaryUnknownType = new IntentSummary("UnknownType"); + } + + /** + * Collects summary of all intents. + * + * @param service the Intent Service to use + * @param intents the intents + */ + private void collectIntentSummary(IntentService service, + Iterable<Intent> intents) { + init(); + + // Collect the summary for each intent type intents + for (Intent intent : intents) { + IntentState intentState = service.getIntentState(intent.key()); + if (intentState == null) { + continue; + } + + // Update the summary for all Intents + summaryAll.update(intentState); + + if (intent instanceof ConnectivityIntent) { + summaryConnectivity.update(intentState); + // NOTE: ConnectivityIntent is a base type Intent + // continue; + } + if (intent instanceof HostToHostIntent) { + summaryHostToHost.update(intentState); + continue; + } + if (intent instanceof PointToPointIntent) { + summaryPointToPoint.update(intentState); + continue; + } + if (intent instanceof MultiPointToSinglePointIntent) { + summaryMultiPointToSinglePoint.update(intentState); + continue; + } + if (intent instanceof SinglePointToMultiPointIntent) { + summarySinglePointToMultiPoint.update(intentState); + continue; + } + if (intent instanceof PathIntent) { + summaryPath.update(intentState); + continue; + } + if (intent instanceof LinkCollectionIntent) { + summaryLinkCollection.update(intentState); + continue; + } + + summaryUnknownType.update(intentState); + } + } + + /** + * Gets JSON representation of all Intents summary. + * + * @return JSON representation of all Intents summary + */ + ObjectNode json() { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode result = mapper.createObjectNode(); + result.set("connectivity", summaryConnectivity.json(mapper)); + result.set("hostToHost", summaryHostToHost.json(mapper)); + result.set("pointToPoint", summaryPointToPoint.json(mapper)); + result.set("multiPointToSinglePoint", + summaryMultiPointToSinglePoint.json(mapper)); + result.set("singlePointToMultiPoint", + summarySinglePointToMultiPoint.json(mapper)); + result.set("path", summaryPath.json(mapper)); + result.set("linkCollection", summaryLinkCollection.json(mapper)); + result.set("unknownType", summaryUnknownType.json(mapper)); + result.set("all", summaryAll.json(mapper)); + return result; + } + + /** + * Prints summary of the intents. + */ + private void printSummary() { + summaryConnectivity.printState(); + summaryHostToHost.printState(); + summaryPointToPoint.printState(); + summaryMultiPointToSinglePoint.printState(); + summarySinglePointToMultiPoint.printState(); + summaryPath.printState(); + summaryLinkCollection.printState(); + summaryUnknownType.printState(); + summaryAll.printState(); + } + + /** + * Internal local class to keep track of a single type Intent summary. + */ + private class IntentSummary { + private final String intentType; + private int total = 0; + private int installReq = 0; + private int compiling = 0; + private int installing = 0; + private int installed = 0; + private int recompiling = 0; + private int withdrawReq = 0; + private int withdrawing = 0; + private int withdrawn = 0; + private int failed = 0; + private int unknownState = 0; + + private static final String FORMAT_SUMMARY_LINE1 = + "%-23s total= %7d installed= %7d"; + private static final String FORMAT_SUMMARY_LINE2 = + "%-23s withdrawn= %7d failed= %7d"; + private static final String FORMAT_SUMMARY_LINE3 = + "%-23s installReq= %7d compiling= %7d"; + private static final String FORMAT_SUMMARY_LINE4 = + "%-23s installing= %7d recompiling= %7d"; + private static final String FORMAT_SUMMARY_LINE5 = + "%-23s withdrawReq= %7d withdrawing= %7d"; + private static final String FORMAT_SUMMARY_LINE6 = + "%-23s unknownState= %7d"; + + /** + * Constructor. + * + * @param intentType the scring describing the Intent type + */ + IntentSummary(String intentType) { + this.intentType = intentType; + } + + /** + * Updates the Intent Summary. + * + * @param intentState the state of the Intent + */ + void update(IntentState intentState) { + total++; + switch (intentState) { + case INSTALL_REQ: + installReq++; + break; + case COMPILING: + compiling++; + break; + case INSTALLING: + installing++; + break; + case INSTALLED: + installed++; + break; + case RECOMPILING: + recompiling++; + break; + case WITHDRAW_REQ: + withdrawReq++; + break; + case WITHDRAWING: + withdrawing++; + break; + case WITHDRAWN: + withdrawn++; + break; + case FAILED: + failed++; + break; + default: + unknownState++; + break; + } + } + + /** + * Prints the Intent Summary. + */ + void printState() { + print(FORMAT_SUMMARY_LINE1, intentType, total, installed); + print(FORMAT_SUMMARY_LINE2, intentType, withdrawn, failed); + print(FORMAT_SUMMARY_LINE3, intentType, installReq, compiling); + print(FORMAT_SUMMARY_LINE4, intentType, installing, recompiling); + print(FORMAT_SUMMARY_LINE5, intentType, withdrawReq, withdrawing); + if (unknownState != 0) { + print(FORMAT_SUMMARY_LINE6, intentType, unknownState); + } + } + + /** + * Gets the JSON representation of the Intent Summary. + * + * @return the JSON representation of the Intent Summary + */ + JsonNode json(ObjectMapper mapper) { + ObjectNode result = mapper.createObjectNode() + .put("total", total) + .put("installed", installed) + .put("failed", failed) + .put("installReq", installReq) + .put("compiling", compiling) + .put("installing", installing) + .put("recompiling", recompiling) + .put("withdrawReq", withdrawReq) + .put("withdrawing", withdrawing) + .put("withdrawn", withdrawn) + .put("unknownState", unknownState); + + return result; + } + } + } + + private void printDetails(IntentService service, Intent intent) { + if (!intent.resources().isEmpty()) { + print(" resources=%s", intent.resources()); + } + if (intent instanceof ConnectivityIntent) { + ConnectivityIntent ci = (ConnectivityIntent) intent; + if (!ci.selector().criteria().isEmpty()) { + print(" selector=%s", ci.selector().criteria()); + } + if (!ci.treatment().allInstructions().isEmpty()) { + print(" treatment=%s", ci.treatment().allInstructions()); + } + if (ci.constraints() != null && !ci.constraints().isEmpty()) { + print(" constraints=%s", ci.constraints()); + } + } + + if (intent instanceof HostToHostIntent) { + HostToHostIntent pi = (HostToHostIntent) intent; + print(" 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()); + } else if (intent instanceof MultiPointToSinglePointIntent) { + MultiPointToSinglePointIntent pi = (MultiPointToSinglePointIntent) intent; + print(" 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()); + } else if (intent instanceof PathIntent) { + PathIntent pi = (PathIntent) intent; + print(" 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()); + } + + List<Intent> installable = service.getInstallableIntents(intent.key()); + if (showInstallable && installable != null && !installable.isEmpty()) { + print(" installable=%s", installable); + } + } + + // Produces JSON array of the specified intents. + 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))); + return result; + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/InterfacesListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/InterfacesListCommand.java new file mode 100644 index 00000000..aa93eb94 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/InterfacesListCommand.java @@ -0,0 +1,52 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import com.google.common.collect.Lists; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cli.Comparators; +import org.onosproject.incubator.net.intf.Interface; +import org.onosproject.incubator.net.intf.InterfaceService; + +import java.util.Collections; +import java.util.List; + +/** + * Lists all configured interfaces. + */ +@Command(scope = "onos", name = "interfaces", + description = "Lists all configured interfaces.") +public class InterfacesListCommand extends AbstractShellCommand { + + private static final String FORMAT = + "port=%s/%s, ips=%s, mac=%s, vlan=%s"; + + @Override + protected void execute() { + InterfaceService interfaceService = get(InterfaceService.class); + + List<Interface> interfaces = Lists.newArrayList(interfaceService.getInterfaces()); + + Collections.sort(interfaces, Comparators.INTERFACES_COMPARATOR); + + for (Interface intf : interfaces) { + print(FORMAT, intf.connectPoint().deviceId(), intf.connectPoint().port(), + intf.ipAddresses(), intf.mac(), intf.vlan()); + } + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IpProtocol.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IpProtocol.java new file mode 100644 index 00000000..5e0d865e --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IpProtocol.java @@ -0,0 +1,80 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.onlab.packet.IPv4; +import org.onlab.packet.IPv6; + +/** + * Known protocol values for IP protocol field that can be supplied to the CLI. + */ +public enum IpProtocol { + /** ICMP. **/ + ICMP(IPv4.PROTOCOL_ICMP), + /** TCP. **/ + TCP(IPv4.PROTOCOL_TCP), + /** UDP. **/ + UDP(IPv4.PROTOCOL_UDP), + /** ICMP6. **/ + ICMP6(IPv6.PROTOCOL_ICMP6); + + private short value; + + /** + * Constructs an IpProtocol with the given value. + * + * @param value value to use when this IpProtocol is seen + */ + private IpProtocol(short value) { + this.value = value; + } + + /** + * Gets the value to use for this IpProtocol. + * + * @return short value to use for this IpProtocol + */ + public short value() { + return this.value; + } + + /** + * Parse a string input that could contain an IpProtocol value. The value + * may appear in the string either as a known protocol name (one of the + * values of this enum), or a numeric protocol value. + * + * @param input the input string to parse + * @return the numeric value of the parsed IP protocol + * @throws IllegalArgumentException if the input string does not contain a + * value that can be parsed into an IP protocol + */ + public static short parseFromString(String input) { + try { + return valueOf(input).value(); + } catch (IllegalArgumentException e) { + // The input is not a known IP protocol name, let's see if it's an IP + // protocol value (byte). We parse with Short to handle unsigned values + // correctly. + try { + return Short.parseShort(input); + } catch (NumberFormatException e1) { + throw new IllegalArgumentException( + "IpProtocol value must be either a string protocol name" + + " or an 8-bit protocol value"); + } + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IpProtocolCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IpProtocolCompleter.java new file mode 100644 index 00000000..ec02b1da --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/IpProtocolCompleter.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import java.util.List; +import java.util.SortedSet; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; + +/** + * IP protocol completer. + */ +public class IpProtocolCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + SortedSet<String> strings = delegate.getStrings(); + + for (IpProtocol ip : IpProtocol.values()) { + strings.add(ip.toString()); + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LabelApplyCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LabelApplyCommand.java new file mode 100644 index 00000000..c88d41c4 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LabelApplyCommand.java @@ -0,0 +1,59 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import java.util.Collection; +import java.util.Iterator; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.DeviceId; +import org.onosproject.incubator.net.resource.label.DefaultLabelResource; +import org.onosproject.incubator.net.resource.label.LabelResource; +import org.onosproject.incubator.net.resource.label.LabelResourceService; + +@Command(scope = "onos", name = "label-apply", + description = "Apply label resource from device pool by specific device id") +public class LabelApplyCommand extends AbstractShellCommand { + @Argument(index = 0, name = "deviceId", + description = "Device identity", + required = true, multiValued = false) + String deviceId = null; + @Argument(index = 1, name = "applyNum", + description = "Applying number means how many labels applications want to use.", + required = true, multiValued = false) + String applyNum = null; + + private static final String FMT = "deviceid=%s, labelresourceid=%s"; + + @Override + protected void execute() { + LabelResourceService lrs = get(LabelResourceService.class); + Collection<LabelResource> result = lrs.applyFromDevicePool(DeviceId + .deviceId(deviceId), Long.parseLong(applyNum)); + if (result.size() > 0) { + for (Iterator<LabelResource> iterator = result.iterator(); iterator + .hasNext();) { + DefaultLabelResource defaultLabelResource = (DefaultLabelResource) iterator + .next(); + print(FMT, defaultLabelResource.deviceId().toString(), + defaultLabelResource.labelResourceId().toString()); + } + } + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LabelPoolCreateCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LabelPoolCreateCommand.java new file mode 100644 index 00000000..78a6d196 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LabelPoolCreateCommand.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.DeviceId; +import org.onosproject.incubator.net.resource.label.LabelResourceAdminService; +import org.onosproject.incubator.net.resource.label.LabelResourceId; + +/** + * create label resource pool by specific device id. + */ +@Command(scope = "onos", name = "label-pool-create", + description = "Creates label resource pool by a specific device id") +public class LabelPoolCreateCommand extends AbstractShellCommand { + @Argument(index = 0, name = "deviceId", description = "Device identity", required = true, multiValued = false) + String deviceId = null; + @Argument(index = 1, name = "beginLabel", + description = "The first label of global label resource pool.", required = true, multiValued = false) + String beginLabel = null; + @Argument(index = 2, name = "endLabel", + description = "The last label of global label resource pool.", required = true, multiValued = false) + String endLabel = null; + + @Override + protected void execute() { + LabelResourceAdminService lrs = get(LabelResourceAdminService.class); + lrs.createDevicePool(DeviceId.deviceId(deviceId), LabelResourceId + .labelResourceId(Long.parseLong(beginLabel)), LabelResourceId + .labelResourceId(Long.parseLong(endLabel))); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LabelPoolDestroyCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LabelPoolDestroyCommand.java new file mode 100644 index 00000000..6445de63 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LabelPoolDestroyCommand.java @@ -0,0 +1,36 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.DeviceId; +import org.onosproject.incubator.net.resource.label.LabelResourceAdminService; + +@Command(scope = "onos", name = "label-pool-destroy", + description = "Destroys label resource pool by a specific device id") +public class LabelPoolDestroyCommand extends AbstractShellCommand { + @Argument(index = 0, name = "deviceId", description = "Device identity", required = true, multiValued = false) + String deviceId = null; + + @Override + protected void execute() { + LabelResourceAdminService lrs = get(LabelResourceAdminService.class); + lrs.destroyDevicePool(DeviceId.deviceId(deviceId)); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LabelReleaseCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LabelReleaseCommand.java new file mode 100644 index 00000000..cc52204c --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LabelReleaseCommand.java @@ -0,0 +1,59 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.DeviceId; +import org.onosproject.incubator.net.resource.label.DefaultLabelResource; +import org.onosproject.incubator.net.resource.label.LabelResource; +import org.onosproject.incubator.net.resource.label.LabelResourceId; +import org.onosproject.incubator.net.resource.label.LabelResourceService; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; + +@Command(scope = "onos", name = "label-release", +description = "Releases label ids to label resource pool by a specific device id") +public class LabelReleaseCommand extends AbstractShellCommand { + @Argument(index = 0, name = "deviceId", + description = "Device identity", + required = true, multiValued = false) + String deviceId = null; + @Argument(index = 1, name = "releaseLabelIds", + description = "Represents for the label ids that are released. They are splited by dot symbol", + required = true, multiValued = false) + String releaseLabelIds = null; + + @Override + protected void execute() { + LabelResourceService lrs = get(LabelResourceService.class); + Multimap<DeviceId, LabelResource> map = ArrayListMultimap + .create(); + String[] labelIds = releaseLabelIds.split(","); + DefaultLabelResource resource = null; + for (int i = 0; i < labelIds.length; i++) { + resource = new DefaultLabelResource( + DeviceId.deviceId(deviceId), + LabelResourceId.labelResourceId(Long + .parseLong(labelIds[i]))); + map.put(DeviceId.deviceId(deviceId), resource); + } + lrs.releaseToDevicePool(map); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LabelResourceCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LabelResourceCommand.java new file mode 100644 index 00000000..fe263c68 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LabelResourceCommand.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.DeviceId; +import org.onosproject.incubator.net.resource.label.LabelResourcePool; +import org.onosproject.incubator.net.resource.label.LabelResourceService; + +@Command(scope = "onos", name = "label-pool", + description = "Gets label resource pool information by a specific device id") +public class LabelResourceCommand extends AbstractShellCommand { + @Argument(index = 0, name = "deviceId", + description = "Device identity", required = true, multiValued = false) + String deviceId = null; + private static final String FMT = "deviceid=%s, beginLabel=%s," + + "endLabel=%s, totalNum=%s, usedNum=%s, currentUsedMaxLabelId=%s," + + "releaseLabelIds=%s"; + + @Override + protected void execute() { + LabelResourceService lrs = get(LabelResourceService.class); + LabelResourcePool pool = lrs.getDeviceLabelResourcePool(DeviceId + .deviceId(deviceId)); + if (pool != null) { + print(FMT, pool.deviceId().toString(), pool.beginLabel(), + pool.endLabel(), pool.totalNum(), pool.usedNum(), + pool.currentUsedMaxLabelId(), pool.releaseLabelId() + .toString()); + } else { + print(FMT, deviceId, null, null, null, null, null, null); + } + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LeaderCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LeaderCommand.java new file mode 100644 index 00000000..da4ab13a --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LeaderCommand.java @@ -0,0 +1,194 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +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.Tools; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.cluster.Leadership; +import org.onosproject.cluster.LeadershipService; +import org.onosproject.cluster.NodeId; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; + +/** + * Prints the leader for every topic. + */ +@Command(scope = "onos", name = "leaders", + description = "Finds the leader for particular topic.") +public class LeaderCommand extends AbstractShellCommand { + + private static final String FMT = "%-30s | %-15s | %-6s | %-10s |"; + private static final String FMT_C = "%-30s | %-15s | %-19s |"; + private boolean allTopics; + private Pattern pattern; + + @Argument(index = 0, name = "topic", description = "A leadership topic. Can be a regex", + required = false, multiValued = false) + String topicPattern = null; + + @Option(name = "-c", aliases = "--candidates", + description = "List candidate Nodes for each topic's leadership race", + required = false, multiValued = false) + private boolean showCandidates = false; + + /** + * Compares leaders, sorting by toString() output. + */ + private Comparator<Leadership> leadershipComparator = + (e1, e2) -> { + if (e1.leader() == null && e2.leader() == null) { + return 0; + } + if (e1.leader() == null) { + return 1; + } + if (e2.leader() == null) { + return -1; + } + return e1.leader().toString().compareTo(e2.leader().toString()); + }; + + /** + * Displays text representing the leaders. + * + * @param leaderBoard map of leaders + */ + private void displayLeaders(Map<String, Leadership> leaderBoard) { + print("------------------------------------------------------------------------"); + print(FMT, "Topic", "Leader", "Epoch", "Elected"); + print("------------------------------------------------------------------------"); + + leaderBoard.values() + .stream() + .filter(l -> allTopics || pattern.matcher(l.topic()).matches()) + .sorted(leadershipComparator) + .forEach(l -> print(FMT, + l.topic(), + l.leader(), + l.epoch(), + Tools.timeAgo(l.electedTime()))); + print("------------------------------------------------------------------------"); + } + + private void displayCandidates(Map<String, Leadership> leaderBoard, + Map<String, List<NodeId>> candidates) { + print("------------------------------------------------------------------------"); + print(FMT_C, "Topic", "Leader", "Candidates"); + print("------------------------------------------------------------------------"); + candidates + .entrySet() + .stream() + .filter(es -> allTopics || pattern.matcher(es.getKey()).matches()) + .forEach(es -> { + List<NodeId> list = es.getValue(); + if (list == null || list.isEmpty()) { + return; + } + Leadership l = leaderBoard.get(es.getKey()); + print(FMT_C, + es.getKey(), + l == null ? "null" : l.leader(), + // formatting hacks to get it into a table + list.get(0).toString()); + list.subList(1, list.size()).forEach(n -> print(FMT_C, " ", " ", n)); + print(FMT_C, " ", " ", " "); + }); + print("------------------------------------------------------------------------"); + } + + /** + * Returns JSON node representing the leaders. + * + * @param leaderBoard map of leaders + */ + private JsonNode json(Map<String, Leadership> leaderBoard) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode result = mapper.createArrayNode(); + leaderBoard.values() + .stream() + .sorted(leadershipComparator) + .forEach(l -> + result.add( + mapper.createObjectNode() + .put("topic", l.topic()) + .put("leader", l.leader().toString()) + .put("candidates", l.candidates().toString()) + .put("epoch", l.epoch()) + .put("electedTime", Tools.timeAgo(l.electedTime())))); + + return result; + } + + /** + * Returns JSON node representing the leaders. + * + * @param leaderBoard map of leaders + */ + private JsonNode json(Map<String, Leadership> leaderBoard, + Map<String, List<NodeId>> candidateBoard) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode result = mapper.createArrayNode(); + candidateBoard.entrySet() + .stream() + .forEach(es -> { + Leadership l = leaderBoard.get(es.getKey()); + result.add( + mapper.createObjectNode() + .put("topic", es.getKey()) + .put("leader", l == null ? "none" : l.leader().toString()) + .put("candidates", es.getValue().toString())); + }); + return result; + } + + @Override + protected void execute() { + LeadershipService leaderService = get(LeadershipService.class); + Map<String, Leadership> leaderBoard = leaderService.getLeaderBoard(); + if (topicPattern == null) { + allTopics = true; + } else { + allTopics = false; + pattern = Pattern.compile(topicPattern); + } + + if (showCandidates) { + Map<String, List<NodeId>> candidates = leaderService + .getCandidates(); + if (outputJson()) { + print("%s", json(leaderBoard, candidates)); + } else { + displayCandidates(leaderBoard, candidates); + } + } else { + if (outputJson()) { + print("%s", json(leaderBoard)); + } else { + displayLeaders(leaderBoard); + } + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LinkDstCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LinkDstCompleter.java new file mode 100644 index 00000000..626777e3 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LinkDstCompleter.java @@ -0,0 +1,59 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.console.completer.ArgumentCompleter; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.cli.AbstractCompleter; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.link.LinkService; + +import java.util.List; +import java.util.SortedSet; + +/** + * Link destination end-point completer. + */ +public class LinkDstCompleter extends AbstractCompleter { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + + // Fetch our service and feed it's offerings to the string completer + LinkService service = AbstractShellCommand.get(LinkService.class); + + // Link source the previous argument. + ArgumentCompleter.ArgumentList list = getArgumentList(); + String srcArg = list.getArguments()[list.getCursorArgumentIndex() - 1]; + + // Generate the device ID/port number identifiers + SortedSet<String> strings = delegate.getStrings(); + try { + ConnectPoint src = ConnectPoint.deviceConnectPoint(srcArg); + service.getEgressLinks(src) + .forEach(link -> strings.add(link.dst().elementId().toString() + + "/" + link.dst().port())); + } catch (NumberFormatException e) { + System.err.println("Invalid connect-point"); + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LinkResourceTestCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LinkResourceTestCommand.java new file mode 100644 index 00000000..d68084c7 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LinkResourceTestCommand.java @@ -0,0 +1,123 @@ +package org.onosproject.cli.net; + +import java.util.Set; +import java.util.List; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.intent.IntentId; +import org.onosproject.net.resource.link.DefaultLinkResourceRequest; +import org.onosproject.net.resource.link.LinkResourceAllocations; +import org.onosproject.net.resource.link.LinkResourceRequest; +import org.onosproject.net.resource.link.LinkResourceService; +import org.onosproject.net.topology.PathService; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Path; + +import com.google.common.collect.Lists; + +/** + * Commands to test out LinkResourceManager directly. + */ +@Command(scope = "onos", name = "resource-request", + description = "request or remove resources") +public class LinkResourceTestCommand extends AbstractShellCommand { + + // default is bandwidth. + @Option(name = "-m", aliases = "--mpls", description = "MPLS resource", + required = false, multiValued = false) + private boolean isMPLS = false; + + @Option(name = "-o", aliases = "--optical", description = "Optical resource", + required = false, multiValued = false) + private boolean isOptical = false; + + @Option(name = "-d", aliases = "--delete", description = "Delete resource by intent ID", + required = false, multiValued = false) + private boolean remove = false; + + @Argument(index = 0, name = "srcString", description = "Link source", + required = true, multiValued = false) + String srcString = null; + + @Argument(index = 1, name = "dstString", description = "Link destination", + required = true, multiValued = false) + String dstString = null; + + @Argument(index = 2, name = "id", description = "Identifier", + required = true, multiValued = false) + int id; + + private LinkResourceService resService; + private PathService pathService; + + private static final int BANDWIDTH = 1_000_000; + + @Override + protected void execute() { + resService = get(LinkResourceService.class); + pathService = get(PathService.class); + + DeviceId src = DeviceId.deviceId(getDeviceId(srcString)); + DeviceId dst = DeviceId.deviceId(getDeviceId(dstString)); + IntentId intId = IntentId.valueOf(id); + + Set<Path> paths = pathService.getPaths(src, dst); + + if (paths == null || paths.isEmpty()) { + print("No path between %s and %s", srcString, dstString); + return; + } + + if (remove) { + LinkResourceAllocations lra = resService.getAllocations(intId); + resService.releaseResources(lra); + return; + } + + for (Path p : paths) { + List<Link> links = p.links(); + LinkResourceRequest.Builder request = null; + if (isMPLS) { + List<Link> nlinks = Lists.newArrayList(); + try { + nlinks.addAll(links.subList(1, links.size() - 2)); + request = DefaultLinkResourceRequest.builder(intId, nlinks) + .addMplsRequest(); + } catch (IndexOutOfBoundsException e) { + log.warn("could not allocate MPLS path", e); + continue; + } + } else if (isOptical) { + request = DefaultLinkResourceRequest.builder(intId, links) + .addLambdaRequest(); + } else { + request = DefaultLinkResourceRequest.builder(intId, links) + .addBandwidthRequest(BANDWIDTH); + } + + if (request != null) { + LinkResourceRequest lrr = request.build(); + LinkResourceAllocations lra = resService.requestResources(lrr); + if (lra != null) { + break; + } + print("Allocated:\n%s", lra); + } else { + log.info("nothing to request"); + } + } + } + + public String getDeviceId(String deviceString) { + int slash = deviceString.indexOf('/'); + if (slash <= 0) { + return ""; + } + return deviceString.substring(0, slash); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LinkSrcCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LinkSrcCompleter.java new file mode 100644 index 00000000..f957f77f --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LinkSrcCompleter.java @@ -0,0 +1,48 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.cli.AbstractCompleter; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.link.LinkService; + +import java.util.List; +import java.util.SortedSet; + +/** + * Link source end-point completer. + */ +public class LinkSrcCompleter extends AbstractCompleter { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + + // Fetch our service and feed it's offerings to the string completer + LinkService service = AbstractShellCommand.get(LinkService.class); + + // Generate the device ID/port number identifiers + SortedSet<String> strings = delegate.getStrings(); + service.getLinks() + .forEach(link -> strings.add(link.src().elementId().toString() + + "/" + link.src().port())); + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LinksListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LinksListCommand.java new file mode 100644 index 00000000..b9403a39 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/LinksListCommand.java @@ -0,0 +1,110 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.Link; +import org.onosproject.net.link.LinkService; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static org.onosproject.net.DeviceId.deviceId; + +/** + * Lists all infrastructure links. + */ +@Command(scope = "onos", name = "links", + description = "Lists all infrastructure links") +public class LinksListCommand extends AbstractShellCommand { + + private static final String FMT = "src=%s/%s, dst=%s/%s, type=%s, state=%s%s"; + private static final String COMPACT = "%s/%s-%s/%s"; + + @Argument(index = 0, name = "uri", description = "Device ID", + required = false, multiValued = false) + String uri = null; + + @Override + protected void execute() { + LinkService service = get(LinkService.class); + Iterable<Link> links = uri != null ? + service.getDeviceLinks(deviceId(uri)) : service.getLinks(); + if (outputJson()) { + print("%s", json(this, links)); + } else { + for (Link link : links) { + print(linkString(link)); + } + } + } + + /** + * Produces a JSON array containing the specified links. + * + * @param context context to use for looking up codecs + * @param links collection of links + * @return JSON array + */ + public static JsonNode json(AbstractShellCommand context, Iterable<Link> links) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode result = mapper.createArrayNode(); + + links.forEach(link -> result.add(context.jsonForEntity(link, Link.class))); + + return result; + } + + /** + * Produces a JSON object for the specified link. + * + * @param context context to use for looking up codecs + * @param link link to encode + * @return JSON object + */ + public static ObjectNode json(AbstractShellCommand context, Link link) { + return context.jsonForEntity(link, Link.class); + } + + /** + * Returns a formatted string representing the given link. + * + * @param link infrastructure link + * @return formatted link string + */ + public static String linkString(Link link) { + return String.format(FMT, link.src().deviceId(), link.src().port(), + link.dst().deviceId(), link.dst().port(), + link.type(), link.state(), + annotations(link.annotations())); + } + + /** + * Returns a compact string representing the given link. + * + * @param link infrastructure link + * @return formatted link string + */ + public static String compactLinkString(Link link) { + return String.format(COMPACT, link.src().deviceId(), link.src().port(), + link.dst().deviceId(), link.dst().port()); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/MapsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/MapsListCommand.java new file mode 100644 index 00000000..27cc5254 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/MapsListCommand.java @@ -0,0 +1,84 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import java.util.List; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.store.service.MapInfo; +import org.onosproject.store.service.StorageAdminService; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Command to list the various maps in the system. + */ +@Command(scope = "onos", name = "maps", + description = "Lists information about consistent maps in the system") +public class MapsListCommand extends AbstractShellCommand { + + // TODO: Add support to display different eventually + // consistent maps as well. + + private static final String FMT = "name=%s size=%d"; + + /** + * Displays map info as text. + * + * @param mapInfo map descriptions + */ + private void displayMaps(List<MapInfo> mapInfo) { + for (MapInfo info : mapInfo) { + print(FMT, info.name(), info.size()); + } + } + + /** + * Converts list of map info into a JSON object. + * + * @param mapInfo map descriptions + */ + private JsonNode json(List<MapInfo> mapInfo) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode maps = mapper.createArrayNode(); + + // Create a JSON node for each map + mapInfo.stream() + .forEach(info -> { + ObjectNode map = mapper.createObjectNode(); + map.put("name", info.name()) + .put("size", info.size()); + maps.add(map); + }); + + return maps; + } + + @Override + protected void execute() { + StorageAdminService storageAdminService = get(StorageAdminService.class); + List<MapInfo> mapInfo = storageAdminService.getMapInfo(); + if (outputJson()) { + print("%s", json(mapInfo)); + } else { + displayMaps(mapInfo); + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/Meters.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/Meters.java new file mode 100644 index 00000000..76f3813c --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/Meters.java @@ -0,0 +1,58 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import com.google.common.collect.Collections2; +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.DeviceId; +import org.onosproject.net.meter.Meter; +import org.onosproject.net.meter.MeterService; + +import java.util.Collection; + +/** + * Add a meter. + */ +@Command(scope = "onos", name = "meters", + description = "Shows meters") +public class Meters extends AbstractShellCommand { + + @Argument(index = 0, name = "uri", description = "Device ID", + required = false, multiValued = false) + String uri = null; + + + @Override + protected void execute() { + MeterService service = get(MeterService.class); + + Collection<Meter> meters = service.getAllMeters(); + if (uri != null) { + DeviceId deviceId = DeviceId.deviceId(uri); + Collection<Meter> devMeters = Collections2.filter(meters, + m -> m.deviceId().equals(deviceId)); + printMeters(devMeters); + } else { + printMeters(meters); + } + } + + private void printMeters(Collection<Meter> meters) { + meters.forEach(m -> print(" %s", m)); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/PartitionsListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/PartitionsListCommand.java new file mode 100644 index 00000000..8b3d1660 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/PartitionsListCommand.java @@ -0,0 +1,109 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import java.util.List; + +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.store.service.PartitionInfo; +import org.onosproject.store.service.StorageAdminService; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Command to list the database partitions in the system. + */ +@Command(scope = "onos", name = "partitions", + description = "Lists information about partitions in the system") +public class PartitionsListCommand extends AbstractShellCommand { + + private static final String FMT = "%-20s %8s %25s %s"; + + /** + * Displays partition info as text. + * + * @param partitionInfo partition descriptions + */ + private void displayPartitions(List<PartitionInfo> partitionInfo) { + print("----------------------------------------------------------"); + print(FMT, "Name", "Term", "Members", ""); + print("----------------------------------------------------------"); + + for (PartitionInfo info : partitionInfo) { + boolean first = true; + for (String member : info.members()) { + if (first) { + print(FMT, info.name(), info.term(), member, + member.equals(info.leader()) ? "*" : ""); + first = false; + } else { + print(FMT, "", "", member, + member.equals(info.leader()) ? "*" : ""); + } + } + if (!first) { + print("----------------------------------------------------------"); + } + } + } + + /** + * Converts partition info into a JSON object. + * + * @param partitionInfo partition descriptions + */ + private JsonNode json(List<PartitionInfo> partitionInfo) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode partitions = mapper.createArrayNode(); + + // Create a JSON node for each partition + partitionInfo.stream() + .forEach(info -> { + ObjectNode partition = mapper.createObjectNode(); + + // Add each member to the "members" array for this partition + ArrayNode members = partition.putArray("members"); + info.members() + .stream() + .forEach(members::add); + + // Complete the partition attributes and add it to the array + partition.put("name", info.name()) + .put("term", info.term()) + .put("leader", info.leader()); + partitions.add(partition); + + }); + + return partitions; + } + + @Override + protected void execute() { + StorageAdminService storageAdminService = get(StorageAdminService.class); + List<PartitionInfo> partitionInfo = storageAdminService.getPartitionInfo(); + + if (outputJson()) { + print("%s", json(partitionInfo)); + } else { + displayPartitions(partitionInfo); + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/PathListCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/PathListCommand.java new file mode 100644 index 00000000..141ae266 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/PathListCommand.java @@ -0,0 +1,97 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.Link; +import org.onosproject.net.Path; + +import java.util.Set; + +import static org.onosproject.cli.net.LinksListCommand.compactLinkString; +import static org.onosproject.net.DeviceId.deviceId; + +/** + * Lists all shortest-paths paths between the specified source and + * destination devices. + */ +@Command(scope = "onos", name = "paths", + description = "Lists all shortest-paths paths between the specified source and destination devices") +public class PathListCommand extends TopologyCommand { + + private static final String SEP = "==>"; + + @Argument(index = 0, name = "src", description = "Source device ID", + required = true, multiValued = false) + String src = null; + + @Argument(index = 1, name = "dst", description = "Destination device ID", + required = true, multiValued = false) + String dst = null; + + @Override + protected void execute() { + init(); + Set<Path> paths = service.getPaths(topology, deviceId(src), deviceId(dst)); + if (outputJson()) { + print("%s", json(this, paths)); + } else { + for (Path path : paths) { + print(pathString(path)); + } + } + } + + /** + * Produces a JSON array containing the specified paths. + * + * @param context context to use for looking up codecs + * @param paths collection of paths + * @return JSON array + */ + public static JsonNode json(AbstractShellCommand context, Iterable<Path> paths) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode result = mapper.createArrayNode(); + for (Path path : paths) { + result.add(LinksListCommand.json(context, path) + .put("cost", path.cost()) + .set("links", LinksListCommand.json(context, path.links()))); + } + return result; + } + + /** + * Produces a formatted string representing the specified path. + * + * @param path network path + * @return formatted path string + */ + protected String pathString(Path path) { + StringBuilder sb = new StringBuilder(); + for (Link link : path.links()) { + sb.append(compactLinkString(link)).append(SEP); + } + sb.delete(sb.lastIndexOf(SEP), sb.length()); + sb.append("; cost=").append(path.cost()); + return sb.toString(); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/RandomIntentCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/RandomIntentCommand.java new file mode 100644 index 00000000..d917f904 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/RandomIntentCommand.java @@ -0,0 +1,103 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.Host; +import org.onosproject.net.host.HostService; +import org.onosproject.net.intent.HostToHostIntent; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentService; + +import com.google.common.collect.Lists; + +/** + * Installs bulk point-to-point connectivity intents between random ingress/egress devices. + */ +@Command(scope = "onos", name = "push-random-intents", + description = "Installs random intents to test throughput") +public class RandomIntentCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "count", + description = "Number of intents to push", + required = true, multiValued = false) + String countString = null; + + private IntentService service; + private HostService hostService; + private int count; + + @Override + protected void execute() { + service = get(IntentService.class); + hostService = get(HostService.class); + + count = Integer.parseInt(countString); + + if (count > 0) { + Collection<Intent> intents = generateIntents(); + submitIntents(intents); + } else { + withdrawIntents(); + } + } + + private Collection<Intent> generateIntents() { + List<Host> hosts = Lists.newArrayList(hostService.getHosts()); + List<Intent> fullMesh = Lists.newArrayList(); + for (int i = 0; i < hosts.size(); i++) { + for (int j = i + 1; j < hosts.size(); j++) { + fullMesh.add(HostToHostIntent.builder() + .appId(appId()) + .one(hosts.get(i).id()) + .two(hosts.get(j).id()) + .build()); + + } + } + Collections.shuffle(fullMesh); + return fullMesh.subList(0, Math.min(count, fullMesh.size())); + } + + private void submitIntents(Collection<Intent> intents) { + for (Intent intent : intents) { + service.submit(intent); + } + print("Submitted %d host to host intents.", intents.size()); + } + + private void withdrawIntents() { + for (Intent intent : service.getIntents()) { + if (appId().equals(intent.appId())) { + service.withdraw(intent); + } + } + print("Withdrew all randomly generated host to host intents."); + } + + @Override + protected ApplicationId appId() { + return get(CoreService.class).registerApplication("org.onosproject.cli-random"); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ResourceAllocationsCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ResourceAllocationsCommand.java new file mode 100644 index 00000000..9a18bfce --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ResourceAllocationsCommand.java @@ -0,0 +1,64 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Link; +import org.onosproject.net.link.LinkService; +import org.onosproject.net.resource.link.LinkResourceService; + +/** + * Lists allocations by link. Lists all allocations if link is unspecified. + */ +@Command(scope = "onos", name = "resource-allocations", + description = "Lists allocations by link. Lists all allocations if link is unspecified.") +public class ResourceAllocationsCommand extends AbstractShellCommand { + + private static final String FMT = "src=%s/%s, dst=%s/%s, type=%s%s"; + private static final String COMPACT = "%s/%s-%s/%s"; + + @Argument(index = 0, name = "srcString", description = "Link source", + required = false, multiValued = false) + String srcString = null; + @Argument(index = 1, name = "dstString", description = "Link destination", + required = false, multiValued = false) + String dstString = null; + + @Override + protected void execute() { + LinkResourceService resourceService = get(LinkResourceService.class); + LinkService linkService = get(LinkService.class); + + if (srcString == null || dstString == null) { + print("----- Displaying all resource allocations -----"); + resourceService.getAllocations().forEach(alloc -> print("%s", alloc)); + return; + } + + ConnectPoint src = ConnectPoint.deviceConnectPoint(srcString); + ConnectPoint dst = ConnectPoint.deviceConnectPoint(dstString); + + Link link = linkService.getLink(src, dst); + if (link != null) { + resourceService.getAllocations(link).forEach(alloc -> print("%s", alloc)); + } else { + print("No path found for endpoints: %s, %s", src, dst); + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ResourceAvailableCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ResourceAvailableCommand.java new file mode 100644 index 00000000..ab0d3958 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/ResourceAvailableCommand.java @@ -0,0 +1,80 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Link; +import org.onosproject.net.link.LinkService; +import org.onosproject.net.resource.link.LinkResourceService; +import org.onosproject.net.resource.ResourceRequest; + +/** + * Lists allocations by link. + */ +@Command(scope = "onos", name = "resource-available", + description = "Lists available resources by link") +public class ResourceAvailableCommand extends AbstractShellCommand { + + private static final String FMT = "src=%s/%s, dst=%s/%s, type=%s%s"; + private static final String COMPACT = "%s/%s-%s/%s"; + + @Argument(index = 0, name = "srcString", description = "Link source", + required = false, multiValued = false) + String srcString = null; + @Argument(index = 1, name = "dstString", description = "Link destination", + required = false, multiValued = false) + String dstString = null; + + @Override + protected void execute() { + LinkResourceService resourceService = get(LinkResourceService.class); + LinkService linkService = get(LinkService.class); + + Iterable<ResourceRequest> itr = null; + try { + ConnectPoint src = ConnectPoint.deviceConnectPoint(srcString); + + ConnectPoint dst = ConnectPoint.deviceConnectPoint(dstString); + + Link link = linkService.getLink(src, dst); + + itr = resourceService.getAvailableResources(link); + + int lambdaCount = 0; + for (ResourceRequest req : itr) { + switch (req.type()) { + case LAMBDA: + lambdaCount++; + break; + case BANDWIDTH: + print("%s", req); + break; + default: + break; + } + } + if (lambdaCount > 0) { + print("Number of available lambdas: %d", lambdaCount); + } + + } catch (Exception e) { + print("Invalid link %s", e.getMessage()); + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/RoleCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/RoleCompleter.java new file mode 100644 index 00000000..0b4fc97d --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/RoleCompleter.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014 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.onosproject.cli.net; + +import org.apache.karaf.shell.console.Completer; +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.net.MastershipRole; + +import java.util.List; +import java.util.SortedSet; + +/** + * Device mastership role completer. + */ +public class RoleCompleter implements Completer { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + SortedSet<String> strings = delegate.getStrings(); + strings.add(MastershipRole.MASTER.toString().toLowerCase()); + strings.add(MastershipRole.STANDBY.toString().toLowerCase()); + strings.add(MastershipRole.NONE.toString().toLowerCase()); + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TopologyCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TopologyCommand.java new file mode 100644 index 00000000..e1ebd25a --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TopologyCommand.java @@ -0,0 +1,122 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.concurrent.TimeUnit; + +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.net.topology.Topology; +import org.onosproject.net.topology.TopologyProvider; +import org.onosproject.net.topology.TopologyService; + +/** + * Lists summary of the current topology. + */ +@Command(scope = "onos", name = "topology", +description = "Lists summary of the current topology") +public class TopologyCommand extends AbstractShellCommand { + + private static final String FMT = "created=%s, uptime=%s, devices=%d, links=%d, clusters=%d"; + + @Option(name = "-r", aliases = "--recompute", + description = "Trigger topology re-computation", required = false, + multiValued = false) + private boolean recompute = false; + + protected TopologyService service; + protected Topology topology; + + /** + * Initializes the context for all cluster commands. + */ + protected void init() { + service = get(TopologyService.class); + topology = service.currentTopology(); + } + + @Override + protected void execute() { + init(); + long topologyUptime = + Math.max(0, (System.currentTimeMillis() - topology.creationTime())); + if (recompute) { + get(TopologyProvider.class).triggerRecompute(); + + } else if (outputJson()) { + print("%s", + jsonForEntity(topology, Topology.class)); + } else { + print(FMT, formatCreationTime(topology.creationTime()), + formatElapsedTime(topologyUptime), + topology.deviceCount(), topology.linkCount(), + topology.clusterCount()); + } + } + + /** + * Converts millis to a formatted elapsed time string. + * + * @param millis Duration in millis to convert to a string + * + * @return Formatted string: "D days, H hrs, M mins, S secs". + */ + private static String formatElapsedTime(long millis) { + if (millis < 0) { + throw new IllegalArgumentException("Interval less than zero. " + + "Possible unsynchronized timestamps"); + } + + final long days = TimeUnit.MILLISECONDS.toDays(millis); + millis -= TimeUnit.DAYS.toMillis(days); + final long hours = TimeUnit.MILLISECONDS.toHours(millis); + millis -= TimeUnit.HOURS.toMillis(hours); + final long minutes = TimeUnit.MILLISECONDS.toMinutes(millis); + millis -= TimeUnit.MINUTES.toMillis(minutes); + final long seconds = TimeUnit.MILLISECONDS.toSeconds(millis); + + final StringBuilder topologyUptimeString = new StringBuilder(64); + topologyUptimeString.append(days); + topologyUptimeString.append(" days, "); + topologyUptimeString.append(hours); + topologyUptimeString.append(" hrs, "); + topologyUptimeString.append(minutes); + topologyUptimeString.append(" mins, "); + topologyUptimeString.append(seconds); + topologyUptimeString.append(" secs"); + + return (topologyUptimeString.toString()); + } + + /** + * Converts millis to a formatted Date String. + * + * @param millis Duration in millis to convert to a string + * + * @return Formatted string: yyyy-MM-dd HH:mm:ss. + */ + private static String formatCreationTime(long millis) { + final DateFormat dateFormatter = + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(millis); + return (dateFormatter.format(calendar.getTime())); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TransactionsCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TransactionsCommand.java new file mode 100644 index 00000000..6013a389 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TransactionsCommand.java @@ -0,0 +1,98 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import java.util.Collection; + +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onlab.util.Tools; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.store.service.StorageAdminService; +import org.onosproject.store.service.Transaction; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * CLI to work with database transactions in the system. + */ +@Command(scope = "onos", name = "transactions", + description = "Utility for viewing and redriving database transactions") +public class TransactionsCommand extends AbstractShellCommand { + + @Option(name = "-r", aliases = "--redrive", + description = "Redrive stuck transactions while removing those that are done", + required = false, multiValued = false) + private boolean redrive = false; + + private static final String FMT = "%-20s %-15s %-10s"; + + /** + * Displays transactions as text. + * + * @param transactions transactions + */ + private void displayTransactions(Collection<Transaction> transactions) { + print("---------------------------------------------"); + print(FMT, "Id", "State", "Updated"); + print("---------------------------------------------"); + transactions.forEach(txn -> print(FMT, txn.id(), txn.state(), Tools.timeAgo(txn.lastUpdated()))); + if (transactions.size() > 0) { + print("---------------------------------------------"); + } + } + + /** + * Converts collection of transactions into a JSON object. + * + * @param transactions transactions + */ + private JsonNode json(Collection<Transaction> transactions) { + ObjectMapper mapper = new ObjectMapper(); + ArrayNode txns = mapper.createArrayNode(); + + // Create a JSON node for each transaction + transactions.stream().forEach(txn -> { + ObjectNode txnNode = mapper.createObjectNode(); + txnNode.put("id", txn.id()) + .put("state", txn.state().toString()) + .put("lastUpdated", txn.lastUpdated()); + txns.add(txnNode); + }); + + return txns; + } + + @Override + protected void execute() { + StorageAdminService storageAdminService = get(StorageAdminService.class); + + if (redrive) { + storageAdminService.redriveTransactions(); + return; + } + + Collection<Transaction> transactions = storageAdminService.getTransactions(); + if (outputJson()) { + print("%s", json(transactions)); + } else { + displayTransactions(transactions); + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelBorrowCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelBorrowCommand.java new file mode 100644 index 00000000..3db4e865 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelBorrowCommand.java @@ -0,0 +1,212 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Optional; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onlab.packet.IpAddress; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.DefaultApplicationId; +import org.onosproject.incubator.net.tunnel.DefaultOpticalTunnelEndPoint; +import org.onosproject.incubator.net.tunnel.IpTunnelEndPoint; +import org.onosproject.incubator.net.tunnel.OpticalLogicId; +import org.onosproject.incubator.net.tunnel.OpticalTunnelEndPoint; +import org.onosproject.incubator.net.tunnel.Tunnel; +import org.onosproject.incubator.net.tunnel.TunnelEndPoint; +import org.onosproject.incubator.net.tunnel.TunnelId; +import org.onosproject.incubator.net.tunnel.TunnelName; +import org.onosproject.incubator.net.tunnel.TunnelService; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.provider.ProviderId; + +/** + * Borrows tunnels. It's used by consumers. + */ +@Command(scope = "onos", name = "tunnel-borrow", description = "Borrows tunnels. It's used by consumers.") +public class TunnelBorrowCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "consumerId", + description = "consumer id means application id.", required = true, multiValued = false) + String consumerId = null; + + @Option(name = "-s", aliases = "--src", description = "Source tunnel point." + + " Only supports for IpTunnelEndPoint and OpticalTunnelEndPoint as end point now." + + " If deletess a ODUK or OCH type tunnel, the formatter of this argument is DeviceId-PortNumber." + + " Otherwise src means IP address.", required = false, multiValued = false) + String src = null; + + @Option(name = "-d", aliases = "--dst", description = "Destination tunnel point." + + " Only supports for IpTunnelEndPoint and OpticalTunnelEndPoint as end point now." + + " If deletess a ODUK or OCH type tunnel, the formatter of this argument is DeviceId-PortNumber." + + " Otherwise dst means IP address.", required = false, multiValued = false) + String dst = null; + + @Option(name = "-t", aliases = "--type", description = "The type of tunnels," + + " It includes MPLS, VLAN, VXLAN, GRE, ODUK, OCH", required = false, multiValued = false) + String type = null; + + @Option(name = "-i", aliases = "--tunnelId", + description = "the tunnel identity.", required = false, multiValued = false) + String tunnelId = null; + + @Option(name = "-n", aliases = "--tunnelName", + description = "The name of tunnels", required = false, multiValued = false) + String tunnelName = null; + private static final String FMT = "src=%s, dst=%s," + + "type=%s, state=%s, producerName=%s, tunnelName=%s," + + "groupId=%s"; + + @Override + protected void execute() { + Collection<Tunnel> tunnelSet = null; + Tunnel.Type trueType = null; + TunnelService service = get(TunnelService.class); + ApplicationId appId = new DefaultApplicationId(1, consumerId); + ProviderId producerName = new ProviderId("default", + "org.onosproject.provider.tunnel.default"); + if (!isNull(src) && !isNull(dst) && !isNull(type)) { + TunnelEndPoint srcPoint = null; + TunnelEndPoint dstPoint = null; + if ("MPLS".equals(type)) { + trueType = Tunnel.Type.MPLS; + srcPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(src)); + dstPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(dst)); + } else if ("VXLAN".equals(type)) { + trueType = Tunnel.Type.VXLAN; + srcPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(src)); + dstPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(dst)); + } else if ("GRE".equals(type)) { + trueType = Tunnel.Type.GRE; + srcPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(src)); + dstPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(dst)); + } else if ("VLAN".equals(type)) { + trueType = Tunnel.Type.VLAN; + String[] srcArray = src.split("-"); + String[] dstArray = dst.split("-"); + srcPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(srcArray[0])), + Optional.of(PortNumber + .portNumber(srcArray[1])), + null, + null, + OpticalLogicId + .logicId(0), + true); + dstPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(dstArray[0])), + Optional.of(PortNumber + .portNumber(dstArray[1])), + null, + null, + OpticalLogicId + .logicId(0), + true); + } else if ("ODUK".equals(type)) { + trueType = Tunnel.Type.ODUK; + String[] srcArray = src.split("-"); + String[] dstArray = dst.split("-"); + srcPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(srcArray[0])), + Optional.of(PortNumber + .portNumber(srcArray[1])), + null, + OpticalTunnelEndPoint.Type.LAMBDA, + OpticalLogicId + .logicId(0), + true); + dstPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(dstArray[0])), + Optional.of(PortNumber + .portNumber(dstArray[1])), + null, + OpticalTunnelEndPoint.Type.LAMBDA, + OpticalLogicId + .logicId(0), + true); + } else if ("OCH".equals(type)) { + trueType = Tunnel.Type.OCH; + String[] srcArray = src.split("-"); + String[] dstArray = dst.split("-"); + srcPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(srcArray[0])), + Optional.of(PortNumber + .portNumber(srcArray[1])), + null, + OpticalTunnelEndPoint.Type.TIMESLOT, + OpticalLogicId + .logicId(0), + true); + dstPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(dstArray[0])), + Optional.of(PortNumber + .portNumber(dstArray[1])), + null, + OpticalTunnelEndPoint.Type.TIMESLOT, + OpticalLogicId + .logicId(0), + true); + } else { + print("Illegal tunnel type. Please input MPLS, VLAN, VXLAN, GRE, ODUK or OCH."); + return; + } + tunnelSet = service.borrowTunnel(appId, srcPoint, dstPoint, trueType); + } + if (!isNull(tunnelId)) { + TunnelId id = TunnelId.valueOf(tunnelId); + Tunnel tunnel = service.borrowTunnel(appId, id); + tunnelSet = new HashSet<Tunnel>(); + tunnelSet.add(tunnel); + } + if (!isNull(tunnelName)) { + TunnelName name = TunnelName.tunnelName(tunnelName); + tunnelSet = service.borrowTunnel(appId, name); + } + for (Tunnel tunnel : tunnelSet) { + print(FMT, tunnel.src(), tunnel.dst(), tunnel.type(), + tunnel.state(), tunnel.providerId(), tunnel.tunnelName(), + tunnel.groupId()); + } + } + + private boolean isNull(String s) { + return s == null || "".equals(s); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelCreateCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelCreateCommand.java new file mode 100644 index 00000000..955df887 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelCreateCommand.java @@ -0,0 +1,205 @@ +/* + * Copyright 2015 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.onosproject.cli.net; + +import java.util.Optional; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onlab.packet.IpAddress; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.core.DefaultGroupId; +import org.onosproject.incubator.net.tunnel.DefaultOpticalTunnelEndPoint; +import org.onosproject.incubator.net.tunnel.DefaultTunnelDescription; +import org.onosproject.incubator.net.tunnel.IpTunnelEndPoint; +import org.onosproject.incubator.net.tunnel.OpticalLogicId; +import org.onosproject.incubator.net.tunnel.OpticalTunnelEndPoint; +import org.onosproject.incubator.net.tunnel.Tunnel; +import org.onosproject.incubator.net.tunnel.TunnelDescription; +import org.onosproject.incubator.net.tunnel.TunnelEndPoint; +import org.onosproject.incubator.net.tunnel.TunnelId; +import org.onosproject.incubator.net.tunnel.TunnelName; +import org.onosproject.incubator.net.tunnel.TunnelProvider; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.SparseAnnotations; +import org.onosproject.net.provider.ProviderId; + +/** + * Supports for creating a tunnel by using IP address and optical as tunnel end + * point. + */ +@Command(scope = "onos", name = "tunnel-create", +description = "Supports for creating a tunnel by using IP address and optical as tunnel end point now.") +public class TunnelCreateCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "src", description = "Source tunnel point." + + " Only supports for IpTunnelEndPoint and OpticalTunnelEndPoint as end point now." + + " If creates a ODUK or OCH or VLAN type tunnel, the formatter of this argument is DeviceId-PortNumber." + + " Otherwise src means IP address.", required = true, multiValued = false) + String src = null; + + @Argument(index = 1, name = "dst", description = "Destination tunnel point." + + " Only supports for IpTunnelEndPoint and OpticalTunnelEndPoint as end point now." + + " If creates a ODUK or OCH or VLAN type tunnel, the formatter of this argument is DeviceId-PortNumber." + + " Otherwise dst means IP address.", required = true, multiValued = false) + String dst = null; + @Argument(index = 2, name = "type", description = "The type of tunnels," + + " It includes MPLS, VLAN, VXLAN, GRE, ODUK, OCH", required = true, multiValued = false) + String type = null; + @Option(name = "-g", aliases = "--groupId", + description = "Group flow table id which a tunnel match up", required = false, multiValued = false) + String groupId = "0"; + + @Option(name = "-n", aliases = "--tunnelName", + description = "The name of tunnels", required = false, multiValued = false) + String tunnelName = "onos"; + + @Option(name = "-b", aliases = "--bandwidth", + description = "The bandwidth attribute of tunnel", required = false, multiValued = false) + String bandwidth = "1024"; + + private static final String FMT = "The tunnel identity is %s"; + + @Override + protected void execute() { + TunnelProvider service = get(TunnelProvider.class); + ProviderId producerName = new ProviderId("default", + "org.onosproject.provider.tunnel.default"); + TunnelEndPoint srcPoint = null; + TunnelEndPoint dstPoint = null; + Tunnel.Type trueType = null; + if ("MPLS".equals(type)) { + trueType = Tunnel.Type.MPLS; + srcPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(src)); + dstPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(dst)); + } else if ("VLAN".equals(type)) { + trueType = Tunnel.Type.VLAN; + String[] srcArray = src.split("/"); + String[] dstArray = dst.split("/"); + srcPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(srcArray[0])), + Optional.of(PortNumber + .portNumber(srcArray[1])), + null, + null, + OpticalLogicId + .logicId(0), + true); + dstPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(dstArray[0])), + Optional.of(PortNumber + .portNumber(dstArray[1])), + null, + null, + OpticalLogicId + .logicId(0), + true); + } else if ("VXLAN".equals(type)) { + trueType = Tunnel.Type.VXLAN; + srcPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(src)); + dstPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(dst)); + } else if ("GRE".equals(type)) { + trueType = Tunnel.Type.GRE; + srcPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(src)); + dstPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress.valueOf(dst)); + } else if ("ODUK".equals(type)) { + trueType = Tunnel.Type.ODUK; + String[] srcArray = src.split("/"); + String[] dstArray = dst.split("/"); + srcPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(srcArray[0])), + Optional.of(PortNumber + .portNumber(srcArray[1])), + null, + OpticalTunnelEndPoint.Type.LAMBDA, + OpticalLogicId + .logicId(0), + true); + dstPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(dstArray[0])), + Optional.of(PortNumber + .portNumber(dstArray[1])), + null, + OpticalTunnelEndPoint.Type.LAMBDA, + OpticalLogicId + .logicId(0), + true); + } else if ("OCH".equals(type)) { + trueType = Tunnel.Type.OCH; + String[] srcArray = src.split("/"); + String[] dstArray = dst.split("/"); + srcPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(srcArray[0])), + Optional.of(PortNumber + .portNumber(srcArray[1])), + null, + OpticalTunnelEndPoint.Type.TIMESLOT, + OpticalLogicId + .logicId(0), + true); + dstPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(dstArray[0])), + Optional.of(PortNumber + .portNumber(dstArray[1])), + null, + OpticalTunnelEndPoint.Type.TIMESLOT, + OpticalLogicId + .logicId(0), + true); + } else { + print("Illegal tunnel type. Please input MPLS, VLAN, VXLAN, GRE, ODUK or OCH."); + return; + } + + SparseAnnotations annotations = DefaultAnnotations + .builder() + .set("bandwidth", bandwidth == null || "".equals(bandwidth) ? "0" : bandwidth) + .build(); + TunnelDescription tunnel = new DefaultTunnelDescription( + null, + srcPoint, + dstPoint, + trueType, + new DefaultGroupId(Integer.parseInt(groupId)), + producerName, + TunnelName + .tunnelName(tunnelName), + null, + annotations); + TunnelId tunnelId = service.tunnelAdded(tunnel); + if (tunnelId == null) { + error("Create tunnel failed."); + return; + } + print(FMT, tunnelId.id()); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelQueryCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelQueryCommand.java new file mode 100644 index 00000000..c60337c5 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelQueryCommand.java @@ -0,0 +1,224 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Optional; + +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onlab.packet.IpAddress; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.incubator.net.tunnel.DefaultOpticalTunnelEndPoint; +import org.onosproject.incubator.net.tunnel.IpTunnelEndPoint; +import org.onosproject.incubator.net.tunnel.OpticalLogicId; +import org.onosproject.incubator.net.tunnel.OpticalTunnelEndPoint; +import org.onosproject.incubator.net.tunnel.Tunnel; +import org.onosproject.incubator.net.tunnel.TunnelEndPoint; +import org.onosproject.incubator.net.tunnel.TunnelId; +import org.onosproject.incubator.net.tunnel.TunnelService; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.PortNumber; +import org.onosproject.net.provider.ProviderId; + +/** + * Supports for querying tunnels. It's used by consumers. + */ +@Command(scope = "onos", name = "tunnels", description = "Supports for querying tunnels." + + " It's used by consumers.") +public class TunnelQueryCommand extends AbstractShellCommand { + @Option(name = "-s", aliases = "--src", description = "Source tunnel point." + + " Only supports for IpTunnelEndPoint and OpticalTunnelEndPoint as end point now." + + " If deletess a ODUK or OCH type tunnel, the formatter of this argument is DeviceId-PortNumber." + + " Otherwise src means IP address.", required = false, multiValued = false) + String src = null; + @Option(name = "-d", aliases = "--dst", description = "Destination tunnel point." + + " Only supports for IpTunnelEndPoint and OpticalTunnelEndPoint as end point now." + + " If deletess a ODUK or OCH type tunnel, the formatter of this argument is DeviceId-PortNumber." + + " Otherwise dst means IP address.", required = false, multiValued = false) + String dst = null; + + @Option(name = "-t", aliases = "--type", description = "The type of tunnels," + + " It includes MPLS, VLAN, VXLAN, GRE, ODUK, OCH", required = false, multiValued = false) + String type = null; + + @Option(name = "-i", aliases = "--tunnelId", + description = "the tunnel identity.", required = false, multiValued = false) + String tunnelId = null; + + private static final String FMT = "tunnelId=%s, src=%s, dst=%s," + + "type=%s, state=%s, producerName=%s, tunnelName=%s," + + "groupId=%s, path=%s%s"; + + @Override + protected void execute() { + Tunnel.Type trueType = null; + TunnelService service = get(TunnelService.class); + ProviderId producerName = new ProviderId("default", + "org.onosproject.provider.tunnel.default"); + Collection<Tunnel> tunnelSet = null; + if (isNull(src) && isNull(dst) && isNull(type) && isNull(tunnelId)) { + tunnelSet = service.queryAllTunnels(); + } + + if (!isNull(src) && !isNull(dst) && !isNull(type)) { + TunnelEndPoint srcPoint = null; + TunnelEndPoint dstPoint = null; + if ("MPLS".equals(type) || "VXLAN".equals(type) + || "GRE".equals(type)) { + srcPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(src)); + dstPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(dst)); + } else if ("VLAN".equals(type)) { + String[] srcArray = src.split("/"); + String[] dstArray = dst.split("/"); + srcPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(srcArray[0])), + Optional.of(PortNumber + .portNumber(srcArray[1])), + null, + null, + OpticalLogicId + .logicId(0), + true); + dstPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(dstArray[0])), + Optional.of(PortNumber + .portNumber(dstArray[1])), + null, + null, + OpticalLogicId + .logicId(0), + true); + } else if ("ODUK".equals(type)) { + String[] srcArray = src.split("/"); + String[] dstArray = dst.split("/"); + srcPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(srcArray[0])), + Optional.of(PortNumber + .portNumber(srcArray[1])), + null, + OpticalTunnelEndPoint.Type.LAMBDA, + OpticalLogicId + .logicId(0), + true); + dstPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(dstArray[0])), + Optional.of(PortNumber + .portNumber(dstArray[1])), + null, + OpticalTunnelEndPoint.Type.LAMBDA, + OpticalLogicId + .logicId(0), + true); + } else if ("OCH".equals(type)) { + String[] srcArray = src.split("/"); + String[] dstArray = dst.split("/"); + srcPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(srcArray[0])), + Optional.of(PortNumber + .portNumber(srcArray[1])), + null, + OpticalTunnelEndPoint.Type.TIMESLOT, + OpticalLogicId + .logicId(0), + true); + dstPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(dstArray[0])), + Optional.of(PortNumber + .portNumber(dstArray[1])), + null, + OpticalTunnelEndPoint.Type.TIMESLOT, + OpticalLogicId + .logicId(0), + true); + } else { + print("Illegal tunnel type. Please input MPLS, VLAN, VXLAN, GRE, ODUK or OCH."); + return; + } + tunnelSet = service.queryTunnel(srcPoint, dstPoint); + } + if (!isNull(type)) { + if ("MPLS".equals(type)) { + trueType = Tunnel.Type.MPLS; + } else if ("VLAN".equals(type)) { + trueType = Tunnel.Type.VLAN; + } else if ("VXLAN".equals(type)) { + trueType = Tunnel.Type.VXLAN; + } else if ("GRE".equals(type)) { + trueType = Tunnel.Type.GRE; + } else if ("ODUK".equals(type)) { + trueType = Tunnel.Type.ODUK; + } else if ("OCH".equals(type)) { + trueType = Tunnel.Type.OCH; + } else { + print("Illegal tunnel type. Please input MPLS, VLAN, VXLAN, GRE, ODUK or OCH."); + return; + } + tunnelSet = service.queryTunnel(trueType); + } + if (!isNull(tunnelId)) { + TunnelId id = TunnelId.valueOf(tunnelId); + Tunnel tunnel = service.queryTunnel(id); + tunnelSet = new HashSet<Tunnel>(); + tunnelSet.add(tunnel); + } + if (tunnelSet != null) { + for (Tunnel tunnel : tunnelSet) { + print(FMT, tunnel.tunnelId().id(), tunnel.src().toString(), tunnel.dst().toString(), + tunnel.type(), tunnel.state(), tunnel.providerId(), + tunnel.tunnelName(), tunnel.groupId(), + showPath(tunnel.path()), + annotations(tunnel.annotations())); + } + } + } + + private String showPath(Path path) { + if (path == null) { + return "null"; + } + StringBuilder builder = new StringBuilder("("); + for (Link link : path.links()) { + builder.append("(DeviceId:" + link.src().deviceId() + " Port:" + + link.src().port().toString()); + builder.append(" DeviceId:" + link.dst().deviceId() + " Port:" + + link.dst().port().toString() + ")"); + } + builder.append(annotations(path.annotations()) + ")"); + return builder.toString(); + } + + private boolean isNull(String s) { + return s == null || "".equals(s); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelQuerySubscriptionCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelQuerySubscriptionCommand.java new file mode 100644 index 00000000..92db9268 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelQuerySubscriptionCommand.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import java.util.Collection; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.DefaultApplicationId; +import org.onosproject.incubator.net.tunnel.TunnelService; +import org.onosproject.incubator.net.tunnel.TunnelSubscription; + +/** + * Query all tunnel subscriptions of consumer by consumer id. + * It's used by consumers. + */ +@Command(scope = "onos", name = "tunnel-subscriptions", + description = "Query all request orders of consumer by consumer id. It's used by consumers.") +public class TunnelQuerySubscriptionCommand extends AbstractShellCommand { + @Argument(index = 0, name = "consumerId", + description = "consumer id means provider id", + required = true, multiValued = false) + String consumerId = null; + private static final String FMT = "appId=%s, src=%s, dst=%s," + + "type=%s, tunnelId=%s"; + + @Override + protected void execute() { + TunnelService service = get(TunnelService.class); + ApplicationId applicationId = new DefaultApplicationId(1, consumerId); + Collection<TunnelSubscription> tunnelSet = service.queryTunnelSubscription(applicationId); + for (TunnelSubscription order : tunnelSet) { + print(FMT, order.consumerId(), order.src(), order.dst(), + order.type(), order.tunnelId()); + } + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelRemoveCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelRemoveCommand.java new file mode 100644 index 00000000..7d42c2d0 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelRemoveCommand.java @@ -0,0 +1,203 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import java.util.Collection; +import java.util.Optional; + +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onlab.packet.IpAddress; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.incubator.net.tunnel.DefaultOpticalTunnelEndPoint; +import org.onosproject.incubator.net.tunnel.DefaultTunnelDescription; +import org.onosproject.incubator.net.tunnel.IpTunnelEndPoint; +import org.onosproject.incubator.net.tunnel.OpticalLogicId; +import org.onosproject.incubator.net.tunnel.OpticalTunnelEndPoint; +import org.onosproject.incubator.net.tunnel.Tunnel; +import org.onosproject.incubator.net.tunnel.TunnelDescription; +import org.onosproject.incubator.net.tunnel.TunnelEndPoint; +import org.onosproject.incubator.net.tunnel.TunnelId; +import org.onosproject.incubator.net.tunnel.TunnelProvider; +import org.onosproject.incubator.net.tunnel.TunnelService; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.provider.ProviderId; + +/** + * Supports for removing tunnels. It's used by producers. + */ +@Command(scope = "onos", name = "tunnel-remove", description = "Supports for removing tunnels. It's used by producers.") +public class TunnelRemoveCommand extends AbstractShellCommand { + @Option(name = "-s", aliases = "--src", description = "Source tunnel point." + + " Only supports for IpTunnelEndPoint and OpticalTunnelEndPoint as end point now." + + " If deletess a ODUK or OCH type tunnel, the formatter of this argument is DeviceId-PortNumber." + + " Otherwise src means IP address.", required = false, multiValued = false) + String src = null; + @Option(name = "-d", aliases = "--dst", description = "Destination tunnel point." + + " Only supports for IpTunnelEndPoint and OpticalTunnelEndPoint as end point now." + + " If deletess a ODUK or OCH type tunnel, the formatter of this argument is DeviceId-PortNumber." + + " Otherwise dst means IP address.", required = false, multiValued = false) + String dst = null; + + @Option(name = "-t", aliases = "--type", description = "The type of tunnels," + + " It includes MPLS, VLAN, VXLAN, GRE, ODUK, OCH", required = false, multiValued = false) + String type = null; + + @Option(name = "-i", aliases = "--tunnelId", + description = "the tunnel identity.", required = false, multiValued = false) + String tunnelId = null; + + @Override + protected void execute() { + TunnelDescription tunnel = null; + TunnelProvider service = get(TunnelProvider.class); + ProviderId producerName = new ProviderId("default", + "org.onosproject.provider.tunnel.default"); + if (!isNull(src) && !isNull(dst) && !isNull(type)) { + TunnelEndPoint srcPoint = null; + TunnelEndPoint dstPoint = null; + Tunnel.Type trueType = null; + if ("MPLS".equals(type)) { + trueType = Tunnel.Type.MPLS; + srcPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(src)); + dstPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(dst)); + } else if ("VLAN".equals(type)) { + trueType = Tunnel.Type.VLAN; + srcPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(src)); + dstPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(dst)); + } else if ("VXLAN".equals(type)) { + trueType = Tunnel.Type.VXLAN; + srcPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(src)); + dstPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(dst)); + } else if ("GRE".equals(type)) { + trueType = Tunnel.Type.GRE; + srcPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(src)); + dstPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(dst)); + } else if ("ODUK".equals(type)) { + trueType = Tunnel.Type.ODUK; + String[] srcArray = src.split("/"); + String[] dstArray = dst.split("/"); + srcPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(srcArray[0])), + Optional.of(PortNumber + .portNumber(srcArray[1])), + null, + OpticalTunnelEndPoint.Type.LAMBDA, + OpticalLogicId + .logicId(0), + true); + dstPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(dstArray[0])), + Optional.of(PortNumber + .portNumber(dstArray[1])), + null, + OpticalTunnelEndPoint.Type.LAMBDA, + OpticalLogicId + .logicId(0), + true); + } else if ("OCH".equals(type)) { + trueType = Tunnel.Type.OCH; + String[] srcArray = src.split("/"); + String[] dstArray = dst.split("/"); + srcPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(srcArray[0])), + Optional.of(PortNumber + .portNumber(srcArray[1])), + null, + OpticalTunnelEndPoint.Type.LAMBDA, + OpticalLogicId + .logicId(0), + true); + dstPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(dstArray[0])), + Optional.of(PortNumber + .portNumber(dstArray[1])), + null, + OpticalTunnelEndPoint.Type.LAMBDA, + OpticalLogicId + .logicId(0), + true); + } else { + print("Illegal tunnel type. Please input MPLS, VLAN, VXLAN, GRE, ODUK or OCH."); + return; + } + + tunnel = new DefaultTunnelDescription(null, srcPoint, dstPoint, + trueType, null, producerName, + null, null); + service.tunnelRemoved(tunnel); + return; + } + if (!isNull(tunnelId)) { + TunnelId id = TunnelId.valueOf(tunnelId); + tunnel = new DefaultTunnelDescription(id, null, null, null, null, + producerName, null, null); + service.tunnelRemoved(tunnel); + return; + } + + if (!isNull(type)) { + Tunnel.Type trueType = null; + Collection<Tunnel> tunnelSet = null; + TunnelService tunnelService = get(TunnelService.class); + if ("MPLS".equals(type)) { + trueType = Tunnel.Type.MPLS; + } else if ("VLAN".equals(type)) { + trueType = Tunnel.Type.VLAN; + } else if ("VXLAN".equals(type)) { + trueType = Tunnel.Type.VXLAN; + } else if ("GRE".equals(type)) { + trueType = Tunnel.Type.GRE; + } else if ("ODUK".equals(type)) { + trueType = Tunnel.Type.ODUK; + } else if ("OCH".equals(type)) { + trueType = Tunnel.Type.OCH; + } else { + print("Illegal tunnel type. Please input MPLS, VLAN, VXLAN, GRE, ODUK or OCH."); + return; + } + tunnelSet = tunnelService.queryTunnel(trueType); + if (tunnelSet != null) { + for (Tunnel tunnelTemp : tunnelSet) { + tunnel = new DefaultTunnelDescription(tunnelTemp.tunnelId(), null, null, null, null, + producerName, null, null); + service.tunnelRemoved(tunnel); + } + } + } + } + + private boolean isNull(String s) { + return s == null || "".equals(s); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelReturnCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelReturnCommand.java new file mode 100644 index 00000000..2b7d7bbd --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelReturnCommand.java @@ -0,0 +1,198 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import java.util.Optional; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onlab.packet.IpAddress; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.DefaultApplicationId; +import org.onosproject.incubator.net.tunnel.DefaultOpticalTunnelEndPoint; +import org.onosproject.incubator.net.tunnel.IpTunnelEndPoint; +import org.onosproject.incubator.net.tunnel.OpticalLogicId; +import org.onosproject.incubator.net.tunnel.OpticalTunnelEndPoint; +import org.onosproject.incubator.net.tunnel.Tunnel; +import org.onosproject.incubator.net.tunnel.TunnelEndPoint; +import org.onosproject.incubator.net.tunnel.TunnelId; +import org.onosproject.incubator.net.tunnel.TunnelName; +import org.onosproject.incubator.net.tunnel.TunnelService; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.provider.ProviderId; + +/** + * Returns tunnels. It's used by consumers. + */ +@Command(scope = "onos", name = "tunnel-return", +description = "Returns tunnels. It's used by consumers.") +public class TunnelReturnCommand extends AbstractShellCommand { + @Argument(index = 0, name = "consumerId", + description = "consumer id means application id.", required = true, multiValued = false) + String consumerId = null; + + @Option(name = "-s", aliases = "--src", description = "Source tunnel point." + + " Only supports for IpTunnelEndPoint and OpticalTunnelEndPoint as end point now." + + " If deletess a ODUK or OCH type tunnel, the formatter of this argument is DeviceId-PortNumber." + + " Otherwise src means IP address.", required = false, multiValued = false) + String src = null; + + @Option(name = "-d", aliases = "--dst", description = "Destination tunnel point." + + " Only supports for IpTunnelEndPoint and OpticalTunnelEndPoint as end point now." + + " If deletess a ODUK or OCH type tunnel, the formatter of this argument is DeviceId-PortNumber." + + " Otherwise dst means IP address.", required = false, multiValued = false) + String dst = null; + + @Option(name = "-t", aliases = "--type", description = "The type of tunnels," + + " It includes MPLS, VLAN, VXLAN, GRE, ODUK, OCH", required = false, multiValued = false) + String type = null; + + @Option(name = "-i", aliases = "--tunnelId", + description = "the tunnel identity.", required = false, multiValued = false) + String tunnelId = null; + + @Option(name = "-n", aliases = "--tunnelName", + description = "The name of tunnels", required = false, multiValued = false) + String tunnelName = null; + + @Override + protected void execute() { + Tunnel.Type trueType = null; + TunnelService service = get(TunnelService.class); + ApplicationId appId = new DefaultApplicationId(1, consumerId); + ProviderId producerName = new ProviderId("default", + "org.onosproject.provider.tunnel.default"); + if (!isNull(src) && !isNull(dst) && !isNull(type)) { + TunnelEndPoint srcPoint = null; + TunnelEndPoint dstPoint = null; + if ("MPLS".equals(type)) { + trueType = Tunnel.Type.MPLS; + srcPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(src)); + dstPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(dst)); + } else if ("VXLAN".equals(type)) { + trueType = Tunnel.Type.VXLAN; + srcPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(src)); + dstPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(dst)); + } else if ("GRE".equals(type)) { + trueType = Tunnel.Type.GRE; + srcPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(src)); + dstPoint = IpTunnelEndPoint.ipTunnelPoint(IpAddress + .valueOf(dst)); + } else if ("VLAN".equals(type)) { + trueType = Tunnel.Type.VLAN; + String[] srcArray = src.split("-"); + String[] dstArray = dst.split("-"); + srcPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(srcArray[0])), + Optional.of(PortNumber + .portNumber(srcArray[1])), + null, + null, + OpticalLogicId + .logicId(0), + true); + dstPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(dstArray[0])), + Optional.of(PortNumber + .portNumber(dstArray[1])), + null, + null, + OpticalLogicId + .logicId(0), + true); + } else if ("ODUK".equals(type)) { + trueType = Tunnel.Type.ODUK; + String[] srcArray = src.split("-"); + String[] dstArray = dst.split("-"); + srcPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(srcArray[0])), + Optional.of(PortNumber + .portNumber(srcArray[1])), + null, + OpticalTunnelEndPoint.Type.LAMBDA, + OpticalLogicId + .logicId(0), + true); + dstPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(dstArray[0])), + Optional.of(PortNumber + .portNumber(dstArray[1])), + null, + OpticalTunnelEndPoint.Type.LAMBDA, + OpticalLogicId + .logicId(0), + true); + } else if ("OCH".equals(type)) { + trueType = Tunnel.Type.OCH; + String[] srcArray = src.split("-"); + String[] dstArray = dst.split("-"); + srcPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(srcArray[0])), + Optional.of(PortNumber + .portNumber(srcArray[1])), + null, + OpticalTunnelEndPoint.Type.TIMESLOT, + OpticalLogicId + .logicId(0), + true); + dstPoint = new DefaultOpticalTunnelEndPoint( + producerName, + Optional.of(DeviceId + .deviceId(dstArray[0])), + Optional.of(PortNumber + .portNumber(dstArray[1])), + null, + OpticalTunnelEndPoint.Type.TIMESLOT, + OpticalLogicId + .logicId(0), + true); + } else { + print("Illegal tunnel type. Please input MPLS, VLAN, VXLAN, GRE, ODUK or OCH."); + return; + } + service.returnTunnel(appId, srcPoint, dstPoint, trueType); + } + if (!isNull(tunnelId)) { + TunnelId id = TunnelId.valueOf(tunnelId); + service.returnTunnel(appId, id); + } + if (!isNull(tunnelName)) { + TunnelName name = TunnelName.tunnelName(tunnelName); + service.returnTunnel(appId, name); + } + } + private boolean isNull(String s) { + return s == null || "".equals(s); + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelUpdateCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelUpdateCommand.java new file mode 100644 index 00000000..d7065571 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/TunnelUpdateCommand.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.apache.karaf.shell.commands.Option; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.incubator.net.tunnel.DefaultTunnelDescription; +import org.onosproject.incubator.net.tunnel.TunnelDescription; +import org.onosproject.incubator.net.tunnel.TunnelId; +import org.onosproject.incubator.net.tunnel.TunnelProvider; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.SparseAnnotations; + +/** + * Supports for updating a tunnel by tunnel identity. + * It's used by producers. + */ +@Command(scope = "onos", name = "tunnel-update", +description = "Supports for updating a tunnel by tunnel identity." + + " It's used by producers.") +public class TunnelUpdateCommand extends AbstractShellCommand { + @Argument(index = 0, name = "tunnelId", description = "the tunnel identity.", + required = true, multiValued = false) + String tunnelId = null; + + @Option(name = "-b", aliases = "--bandwidth", + description = "The bandwidth attribute of tunnel", required = false, multiValued = false) + String bandwidth = null; + + @Override + protected void execute() { + TunnelProvider service = get(TunnelProvider.class); + TunnelId id = TunnelId.valueOf(tunnelId); + SparseAnnotations annotations = DefaultAnnotations + .builder() + .set("bandwidth", bandwidth) + .build(); + TunnelDescription tunnel = new DefaultTunnelDescription(id, null, + null, + null, null, + null, + null, null, annotations); + service.tunnelUpdated(tunnel); + } + +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/WipeOutCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/WipeOutCommand.java new file mode 100644 index 00000000..c842acff --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/WipeOutCommand.java @@ -0,0 +1,109 @@ +/* + * Copyright 2014-2015 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.onosproject.cli.net; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.net.Device; +import org.onosproject.net.Host; +import org.onosproject.net.Link; +import org.onosproject.net.device.DeviceAdminService; +import org.onosproject.net.host.HostAdminService; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.IntentState; +import org.onosproject.net.link.LinkAdminService; + +/** + * Wipes-out the entire network information base, i.e. devices, links, hosts, intents. + */ +@Command(scope = "onos", name = "wipe-out", + description = "Wipes-out the entire network information base, i.e. devices, links, hosts") +public class WipeOutCommand extends ClustersListCommand { + + private static final String PLEASE = "please"; + + @Argument(index = 0, name = "please", description = "Confirmation phrase", + required = false, multiValued = false) + String please = null; + + @Override + protected void execute() { + if (please == null || !please.equals(PLEASE)) { + print("I'm afraid I can't do that!\nSay: %s", PLEASE); + return; + } + + wipeOutIntents(); + wipeOutHosts(); + wipeOutDevices(); + wipeOutLinks(); + } + + private void wipeOutIntents() { + print("Wiping intents"); + IntentService intentService = get(IntentService.class); + for (Intent intent : intentService.getIntents()) { + if (intentService.getIntentState(intent.key()) != IntentState.WITHDRAWN) { + intentService.withdraw(intent); + } + intentService.purge(intent); + } + } + + private void wipeOutHosts() { + print("Wiping hosts"); + HostAdminService hostAdminService = get(HostAdminService.class); + while (hostAdminService.getHostCount() > 0) { + try { + for (Host host : hostAdminService.getHosts()) { + hostAdminService.removeHost(host.id()); + } + } catch (Exception e) { + log.warn("Unable to wipe-out hosts", e); + } + } + } + + private void wipeOutDevices() { + print("Wiping devices"); + DeviceAdminService deviceAdminService = get(DeviceAdminService.class); + while (deviceAdminService.getDeviceCount() > 0) { + try { + for (Device device : deviceAdminService.getDevices()) { + deviceAdminService.removeDevice(device.id()); + } + } catch (Exception e) { + log.warn("Unable to wipe-out devices", e); + } + } + } + + private void wipeOutLinks() { + print("Wiping links"); + LinkAdminService linkAdminService = get(LinkAdminService.class); + while (linkAdminService.getLinkCount() > 0) { + try { + for (Link link : linkAdminService.getLinks()) { + linkAdminService.removeLinks(link.src()); + linkAdminService.removeLinks(link.dst()); + } + } catch (Exception e) { + log.warn("Unable to wipe-out links", e); + } + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/package-info.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/package-info.java new file mode 100644 index 00000000..fb4ba016 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/net/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2014 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. + */ + +/** + * Administrative console command-line extensions for interacting with the + * network model & services. + */ +package org.onosproject.cli.net; diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/package-info.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/package-info.java new file mode 100644 index 00000000..4d9d3690 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Administrative console command-line extensions. + */ +package org.onosproject.cli; diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/security/ReviewApplicationNameCompleter.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/security/ReviewApplicationNameCompleter.java new file mode 100644 index 00000000..73744f3c --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/security/ReviewApplicationNameCompleter.java @@ -0,0 +1,58 @@ +/* + * Copyright 2015 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.onosproject.cli.security; + +import org.apache.karaf.shell.console.completer.StringsCompleter; +import org.onosproject.app.ApplicationService; +import org.onosproject.app.ApplicationState; +import org.onosproject.cli.AbstractCompleter; +import org.onosproject.core.Application; + +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; + +import static org.onosproject.app.ApplicationState.INSTALLED; +import static org.onosproject.cli.AbstractShellCommand.get; + +/** + * Application name completer for security review command. + */ +public class ReviewApplicationNameCompleter extends AbstractCompleter { + @Override + public int complete(String buffer, int cursor, List<String> candidates) { + // Delegate string completer + StringsCompleter delegate = new StringsCompleter(); + + ApplicationService service = get(ApplicationService.class); + Iterator<Application> it = service.getApplications().iterator(); + SortedSet<String> strings = delegate.getStrings(); + while (it.hasNext()) { + Application app = it.next(); + ApplicationState state = service.getState(app.id()); +// if (previousApps.contains(app.id().name())) { +// continue; +// } + if (state == INSTALLED) { + strings.add(app.id().name()); + } + } + + // Now let the completer do the work for figuring out what to offer. + return delegate.complete(buffer, cursor, candidates); + } +}
\ No newline at end of file diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/security/ReviewCommand.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/security/ReviewCommand.java new file mode 100644 index 00000000..9d17eb23 --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/security/ReviewCommand.java @@ -0,0 +1,122 @@ +/* + * Copyright 2015 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.onosproject.cli.security; + +import org.apache.karaf.shell.commands.Argument; +import org.apache.karaf.shell.commands.Command; +import org.onosproject.app.ApplicationAdminService; +import org.onosproject.cli.AbstractShellCommand; +import org.onosproject.core.Application; +import org.onosproject.core.ApplicationId; +import org.onosproject.security.SecurityAdminService; +import org.onosproject.security.SecurityUtil; + +import java.security.Permission; +import java.util.List; +import java.util.Map; + + +/** + * Application security policy review commands. + */ +@Command(scope = "onos", name = "review", + description = "Application security policy review interface") +public class ReviewCommand extends AbstractShellCommand { + + @Argument(index = 0, name = "name", description = "Application name", + required = true, multiValued = false) + String name = null; + + @Argument(index = 1, name = "accept", description = "Option to accept policy", + required = false, multiValued = false) + String accept = null; + + @Override + protected void execute() { + ApplicationAdminService applicationAdminService = get(ApplicationAdminService.class); + ApplicationId appId = applicationAdminService.getId(name); + if (appId == null) { + print("No such application: %s", name); + return; + } + Application app = applicationAdminService.getApplication(appId); + SecurityAdminService smService = SecurityUtil.getSecurityService(); + if (smService == null) { + print("Security Mode is disabled"); + return; + } + if (accept == null) { + smService.review(appId); + printPolicy(smService, app); + } else if (accept.trim().equals("accept")) { + smService.acceptPolicy(appId); + printPolicy(smService, app); + } else { + print("Unknown command"); + } + } + + private void printPolicy(SecurityAdminService smService, Application app) { + print("\n*******************************"); + print(" SM-ONOS APP REVIEW "); + print("*******************************"); + + print("Application name: %s ", app.id().name()); + print("Application role: " + app.role()); + print("\nDeveloper specified permissions: "); + printMap(smService.getPrintableSpecifiedPermissions(app.id())); + print("\nPermissions granted: "); + printMap(smService.getPrintableGrantedPermissions(app.id())); + print("\nAdditional permissions requested on runtime (POLICY VIOLATIONS): "); + printMap(smService.getPrintableRequestedPermissions(app.id())); + print(""); + + } + private void printMap(Map<Integer, List<Permission>> assortedMap) { + for (Integer type : assortedMap.keySet()) { + switch (type) { + case 0: + for (Permission perm: assortedMap.get(0)) { + print("\t[APP PERMISSION] " + perm.getName()); + } + break; + case 1: + for (Permission perm: assortedMap.get(1)) { + print("\t[NB-ADMIN SERVICE] " + perm.getName() + "(" + perm.getActions() + ")"); + } + break; + case 2: + for (Permission perm: assortedMap.get(2)) { + print("\t[NB SERVICE] " + perm.getName() + "(" + perm.getActions() + ")"); + } + break; + case 3: + for (Permission perm: assortedMap.get(3)) { + print("\t[Other SERVICE] " + perm.getName() + "(" + perm.getActions() + ")"); + } + break; + case 4: + for (Permission perm: assortedMap.get(4)) { + print("\t[Other] " + perm.getClass().getSimpleName() + + " " + perm.getName() + " (" + perm.getActions() + ")"); + } + default: + break; + } + } + } +} diff --git a/framework/src/onos/cli/src/main/java/org/onosproject/cli/security/package-info.java b/framework/src/onos/cli/src/main/java/org/onosproject/cli/security/package-info.java new file mode 100644 index 00000000..e634edab --- /dev/null +++ b/framework/src/onos/cli/src/main/java/org/onosproject/cli/security/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015 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. + */ + +/** + * CLI commands for managing security permissions. + */ +package org.onosproject.cli.security;
\ No newline at end of file diff --git a/framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml new file mode 100644 index 00000000..640868fa --- /dev/null +++ b/framework/src/onos/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml @@ -0,0 +1,464 @@ +<!-- + ~ Copyright 2014 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. + --> +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> + + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0"> + <command> + <action class="org.onosproject.cli.SummaryCommand"/> + </command> + + <command> + <action class="org.onosproject.cli.security.ReviewCommand"/> + <completers> + <ref component-id="reviewAppNameCompleter"/> + </completers> + </command> + + <command> + <action class="org.onosproject.cli.net.FlowObjectiveCompositionCommand"/> + </command> + + <command> + <action class="org.onosproject.cli.app.ApplicationsListCommand"/> + </command> + + <command> + <action class="org.onosproject.cli.app.ApplicationCommand"/> + <completers> + <ref component-id="appCommandCompleter"/> + <ref component-id="appNameCompleter"/> + </completers> + </command> + + <command> + <action class="org.onosproject.cli.cfg.ComponentConfigCommand"/> + <completers> + <ref component-id="cfgCommandCompleter"/> + <ref component-id="componentNameCompleter"/> + <ref component-id="componentPropertyNameCompleter"/> + </completers> + </command> + + <command> + <action class="org.onosproject.cli.cfg.NetworkConfigRegistryCommand"/> + </command> + + <command> + <action class="org.onosproject.cli.cfg.NetworkConfigCommand"/> + </command> + + <command> + <action class="org.onosproject.cli.MetricsListCommand"/> + <completers> + <ref component-id="metricNameCompleter"/> + </completers> + </command> + + <command> + <action class="org.onosproject.cli.NodesListCommand"/> + </command> + + <command> + <action class="org.onosproject.cli.UiViewListCommand"/> + </command> + + <command> + <action class="org.onosproject.cli.RolesCommand"/> + </command> + <command> + <action class="org.onosproject.cli.MastersListCommand"/> + </command> + <command> + <action class="org.onosproject.cli.BalanceMastersCommand"/> + </command> + <command> + <action class="org.onosproject.cli.app.ApplicationIdListCommand"/> + </command> + + <command> + <action class="org.onosproject.cli.net.DriversListCommand"/> + <completers> + <ref component-id="driverNameCompleter"/> + </completers> + </command> + + <command> + <action class="org.onosproject.cli.net.DevicesListCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.DevicePortsListCommand"/> + <completers> + <ref component-id="deviceIdCompleter"/> + </completers> + </command> + <command> + <action class="org.onosproject.cli.net.DeviceRemoveCommand"/> + <completers> + <ref component-id="deviceIdCompleter"/> + </completers> + </command> + <command> + <action class="org.onosproject.cli.net.AddMeter"/> + <completers> + <ref component-id="deviceIdCompleter"/> + </completers> + </command> + <command> + <action class="org.onosproject.cli.net.Meters"/> + <completers> + <ref component-id="deviceIdCompleter"/> + </completers> + </command> + <command> + <action class="org.onosproject.cli.net.DeviceRoleCommand"/> + <completers> + <ref component-id="deviceIdCompleter"/> + <ref component-id="nodeIdCompleter"/> + <ref component-id="roleCompleter"/> + </completers> + </command> + <command> + <action class="org.onosproject.cli.net.AnnotateDeviceCommand"/> + <completers> + <ref component-id="deviceIdCompleter"/> + </completers> + </command> + + <command> + <action class="org.onosproject.cli.net.LinksListCommand"/> + <completers> + <ref component-id="deviceIdCompleter"/> + </completers> + </command> + + <command> + <action class="org.onosproject.cli.net.EdgePortsListCommand"/> + <completers> + <ref component-id="deviceIdCompleter"/> + </completers> + </command> + + <command> + <action class="org.onosproject.cli.net.TopologyCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.PathListCommand"/> + <completers> + <ref component-id="deviceIdCompleter"/> + <ref component-id="deviceIdCompleter"/> + </completers> + </command> + + <command> + <action class="org.onosproject.cli.net.IntentsListCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.IntentRemoveCommand"/> + <completers> + <ref component-id="appIdWithIntentNameCompleter"/> + <ref component-id="intentKeyCompleter"/> + </completers> + </command> + <command> + <action class="org.onosproject.cli.net.IntentPurgeCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.AddHostToHostIntentCommand"/> + <completers> + <ref component-id="hostIdCompleter"/> + <ref component-id="hostIdCompleter"/> + </completers> + <optional-completers> + <entry key="-t" value-ref="ethTypeCompleter"/> + <entry key="--ipProto" value-ref="ipProtocolCompleter"/> + <entry key="--icmp6Type" value-ref="Icmp6TypeCompleter"/> + <entry key="--icmp6Code" value-ref="Icmp6CodeCompleter"/> + <entry key="--extHdr" value-ref="ExtHeaderCompleter"/> + <entry key="-a" value-ref="allAppNameCompleter"/> + </optional-completers> + </command> + <command> + <action class="org.onosproject.cli.net.AddPointToPointIntentCommand"/> + <completers> + <ref component-id="connectPointCompleter"/> + <ref component-id="connectPointCompleter"/> + </completers> + <optional-completers> + <entry key="-t" value-ref="ethTypeCompleter"/> + <entry key="--ipProto" value-ref="ipProtocolCompleter"/> + <entry key="--icmp6Type" value-ref="Icmp6TypeCompleter"/> + <entry key="--icmp6Code" value-ref="Icmp6CodeCompleter"/> + <entry key="--extHdr" value-ref="ExtHeaderCompleter"/> + <entry key="-a" value-ref="allAppNameCompleter"/> + </optional-completers> + </command> + <command> + <action class="org.onosproject.cli.net.AddOpticalIntentCommand"/> + <completers> + <ref component-id="connectPointCompleter"/> + <ref component-id="connectPointCompleter"/> + </completers> + <optional-completers> + <entry key="-a" value-ref="allAppNameCompleter"/> + </optional-completers> + </command> + <command> + <action class="org.onosproject.cli.net.GetStatistics"/> + <completers> + <ref component-id="connectPointCompleter"/> + </completers> + </command> + <command> + <action class="org.onosproject.cli.net.AddMultiPointToSinglePointIntentCommand"/> + <completers> + <ref component-id="connectPointCompleter"/> + </completers> + <optional-completers> + <entry key="-t" value-ref="ethTypeCompleter"/> + <entry key="--ipProto" value-ref="ipProtocolCompleter"/> + <entry key="--icmp6Type" value-ref="Icmp6TypeCompleter"/> + <entry key="--icmp6Code" value-ref="Icmp6CodeCompleter"/> + <entry key="--extHdr" value-ref="ExtHeaderCompleter"/> + <entry key="-a" value-ref="allAppNameCompleter"/> + </optional-completers> + </command> + <command> + <action class="org.onosproject.cli.net.AddSinglePointToMultiPointIntentCommand"/> + <completers> + <ref component-id="connectPointCompleter"/> + </completers> + <optional-completers> + <entry key="-t" value-ref="ethTypeCompleter"/> + <entry key="--ipProto" value-ref="ipProtocolCompleter"/> + <entry key="--icmp6Type" value-ref="Icmp6TypeCompleter"/> + <entry key="--icmp6Code" value-ref="Icmp6CodeCompleter"/> + <entry key="--extHdr" value-ref="ExtHeaderCompleter"/> + <entry key="-a" value-ref="allAppNameCompleter"/> + </optional-completers> + </command> + <command> + <action class="org.onosproject.cli.net.IntentPushTestCommand"/> + <completers> + <ref component-id="connectPointCompleter"/> + <ref component-id="connectPointCompleter"/> + <ref component-id="nullCompleter"/> + </completers> + </command> + <command> + <action class="org.onosproject.cli.net.IntentCycleCommand"/> + <completers> + <ref component-id="connectPointCompleter"/> + <ref component-id="connectPointCompleter"/> + <ref component-id="nullCompleter"/> + </completers> + </command> + <command> + <action class="org.onosproject.cli.net.RandomIntentCommand"/> + <completers> + <ref component-id="nullCompleter"/> + </completers> + </command> + <command> + <action class="org.onosproject.cli.net.ResourceAllocationsCommand"/> + <completers> + <ref component-id="connectPointCompleter"/> + <ref component-id="connectPointCompleter"/> + </completers> + </command> + <command> + <action class="org.onosproject.cli.net.ResourceAvailableCommand"/> + <completers> + <ref component-id="connectPointCompleter"/> + <ref component-id="connectPointCompleter"/> + </completers> + </command> + <command> + <action class="org.onosproject.cli.net.LinkResourceTestCommand"/> + <completers> + <ref component-id="connectPointCompleter"/> + <ref component-id="connectPointCompleter"/> + <null/> + </completers> + </command> + <command> + <action class="org.onosproject.cli.net.ClustersListCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.PartitionsListCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.MapsListCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.CountersListCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.TransactionsCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.ClusterDevicesCommand"/> + <completers> + <ref component-id="clusterIdCompleter"/> + </completers> + </command> + <command> + <action class="org.onosproject.cli.net.ClusterLinksCommand"/> + <completers> + <ref component-id="clusterIdCompleter"/> + </completers> + </command> + + <command> + <action class="org.onosproject.cli.net.HostsListCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.HostRemoveCommand"/> + <completers> + <ref component-id="hostIdCompleter"/> + </completers> + </command> + <command> + <action class="org.onosproject.cli.net.AddressBindingsListCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.InterfacesListCommand"/> + </command> + + <command> + <action class="org.onosproject.cli.net.GroupsListCommand"/> + </command> + + <command> + <action class="org.onosproject.cli.net.DevicePortStatsCommand"/> + </command> + + <command> + <action class="org.onosproject.cli.net.FlowsListCommand"/> + <completers> + <ref component-id="flowRuleStatusCompleter"/> + <ref component-id="deviceIdCompleter"/> + </completers> + </command> + + <command> + <action class="org.onosproject.cli.net.AddTestFlowsCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.LeaderCommand"/> + </command> + + <command> + <action class="org.onosproject.cli.net.WipeOutCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.AddMplsIntent"/> + <completers> + <ref component-id="connectPointCompleter"/> + <ref component-id="connectPointCompleter"/> + </completers> + <optional-completers> + <entry key="-t" value-ref="ethTypeCompleter"/> + <entry key="--ipProto" value-ref="ipProtocolCompleter"/> + <entry key="--icmp6Type" value-ref="Icmp6TypeCompleter"/> + <entry key="--icmp6Code" value-ref="Icmp6CodeCompleter"/> + <entry key="--extHdr" value-ref="ExtHeaderCompleter"/> + <entry key="-a" value-ref="allAppNameCompleter"/> + </optional-completers> + </command> + + <command> + <action class="org.onosproject.cli.net.GlobalLabelCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.LabelResourceCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.GlobalLabelPoolCreateCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.LabelPoolCreateCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.GlobalLabelPoolDestoryCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.LabelPoolDestroyCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.GlobalLabelReleaseCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.LabelReleaseCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.GlobalLabelApplyCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.LabelApplyCommand"/> + </command> + <!-- tunnel commands --> + <command> + <action class="org.onosproject.cli.net.TunnelBorrowCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.TunnelReturnCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.TunnelQueryCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.TunnelQuerySubscriptionCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.TunnelCreateCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.TunnelRemoveCommand"/> + </command> + <command> + <action class="org.onosproject.cli.net.TunnelUpdateCommand"/> + </command> + </command-bundle> + + <bean id="reviewAppNameCompleter" class="org.onosproject.cli.security.ReviewApplicationNameCompleter"/> + <bean id="appCommandCompleter" class="org.onosproject.cli.app.ApplicationCommandCompleter"/> + <bean id="appNameCompleter" class="org.onosproject.cli.app.ApplicationNameCompleter"/> + <bean id="allAppNameCompleter" class="org.onosproject.cli.app.AllApplicationNamesCompleter"/> + <bean id="appIdWithIntentNameCompleter" class="org.onosproject.cli.app.ApplicationIdWithIntentNameCompleter"/> + <bean id="cfgCommandCompleter" class="org.onosproject.cli.cfg.ComponentConfigCommandCompleter"/> + <bean id="componentNameCompleter" class="org.onosproject.cli.cfg.ComponentNameCompleter"/> + <bean id="componentPropertyNameCompleter" class="org.onosproject.cli.cfg.ComponentPropertyNameCompleter"/> + <bean id="nodeIdCompleter" class="org.onosproject.cli.NodeIdCompleter"/> + <bean id="deviceIdCompleter" class="org.onosproject.cli.net.DeviceIdCompleter"/> + <bean id="clusterIdCompleter" class="org.onosproject.cli.net.ClusterIdCompleter"/> + <bean id="roleCompleter" class="org.onosproject.cli.net.RoleCompleter"/> + <bean id="hostIdCompleter" class="org.onosproject.cli.net.HostIdCompleter"/> + <bean id="intentKeyCompleter" class="org.onosproject.cli.net.IntentKeyCompleter"/> + <bean id="flowRuleStatusCompleter" class="org.onosproject.cli.net.FlowRuleStatusCompleter"/> + <bean id="connectPointCompleter" class="org.onosproject.cli.net.ConnectPointCompleter"/> + <bean id="nullCompleter" class="org.apache.karaf.shell.console.completer.NullCompleter"/> + <bean id="ethTypeCompleter" class="org.onosproject.cli.net.EthTypeCompleter"/> + <bean id="ipProtocolCompleter" class="org.onosproject.cli.net.IpProtocolCompleter"/> + <bean id="driverNameCompleter" class="org.onosproject.cli.net.DriverNameCompleter"/> + <bean id="Icmp6TypeCompleter" class="org.onosproject.cli.net.Icmp6TypeCompleter"/> + <bean id="Icmp6CodeCompleter" class="org.onosproject.cli.net.Icmp6CodeCompleter"/> + <bean id="ExtHeaderCompleter" class="org.onosproject.cli.net.ExtHeaderCompleter"/> + + <bean id="startStopCompleter" class="org.onosproject.cli.StartStopCompleter"/> + <bean id="metricNameCompleter" class="org.onosproject.cli.MetricNameCompleter"/> + <bean id="upDownCompleter" class="org.onosproject.cli.UpDownCompleter"/> + +</blueprint> |