Madan Jampani

Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next

Showing 23 changed files with 300 additions and 63 deletions
package org.onlab.onos.fwd;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Dictionary;
import java.util.Set;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -30,11 +35,6 @@ import org.onlab.packet.Ethernet;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import java.util.Dictionary;
import java.util.Set;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Sample reactive forwarding application.
*/
......@@ -206,7 +206,7 @@ public class ReactiveForwarding {
treat.setOutput(portNumber);
FlowRule f = new DefaultFlowRule(context.inPacket().receivedFrom().deviceId(),
builder.build(), treat.build(), PRIORITY, appId, TIMEOUT);
builder.build(), treat.build(), PRIORITY, appId, TIMEOUT, false);
flowRuleService.applyFlowRules(f);
}
......
......@@ -21,7 +21,7 @@ import org.onlab.onos.net.device.DeviceService;
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";
private static final String FMT_HDR = "%s: master=%s, standbys=[ %s]";
@Override
protected void execute() {
......
package org.onlab.onos.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.Command;
import org.onlab.onos.cli.AbstractShellCommand;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.NetworkResource;
import org.onlab.onos.net.intent.ConnectivityIntent;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.net.intent.IntentState;
import org.onlab.onos.net.intent.LinkCollectionIntent;
import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
import org.onlab.onos.net.intent.PathIntent;
import org.onlab.onos.net.intent.PointToPointIntent;
import org.onlab.onos.net.intent.SinglePointToMultiPointIntent;
import java.util.List;
import java.util.Set;
/**
* Lists the inventory of intents and their states.
......@@ -16,11 +32,137 @@ public class IntentsListCommand extends AbstractShellCommand {
@Override
protected void execute() {
IntentService service = get(IntentService.class);
for (Intent intent : service.getIntents()) {
IntentState state = service.getIntentState(intent.id());
print("id=%s, state=%s, appId=%s, %s",
intent.id(), state, intent.appId().name(), intent);
if (outputJson()) {
print("%s", json(service, service.getIntents()));
} else {
for (Intent intent : service.getIntents()) {
IntentState state = service.getIntentState(intent.id());
print("id=%s, state=%s, type=%s, appId=%s",
intent.id(), state, intent.getClass().getSimpleName(),
intent.appId().name());
printDetails(service, intent);
}
}
}
private void printDetails(IntentService service, Intent intent) {
if (intent.resources() != null && !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().instructions().isEmpty()) {
print(" treatment=%s", ci.treatment().instructions());
}
}
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.egressPoint());
}
List<Intent> installable = service.getInstallableIntents(intent.id());
if (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();
for (Intent intent : intents) {
result.add(json(service, mapper, intent));
}
return result;
}
private JsonNode json(IntentService service, ObjectMapper mapper, Intent intent) {
ObjectNode result = mapper.createObjectNode()
.put("id", intent.id().toString())
.put("type", intent.getClass().getSimpleName())
.put("appId", intent.appId().name());
IntentState state = service.getIntentState(intent.id());
if (state != null) {
result.put("state", state.toString());
}
if (intent.resources() != null && !intent.resources().isEmpty()) {
ArrayNode rnode = mapper.createArrayNode();
for (NetworkResource resource : intent.resources()) {
rnode.add(resource.toString());
}
result.set("resources", rnode);
}
if (intent instanceof ConnectivityIntent) {
ConnectivityIntent ci = (ConnectivityIntent) intent;
if (!ci.selector().criteria().isEmpty()) {
result.put("selector", ci.selector().criteria().toString());
}
if (!ci.treatment().instructions().isEmpty()) {
result.put("treatment", ci.treatment().instructions().toString());
}
}
if (intent instanceof PathIntent) {
PathIntent pi = (PathIntent) intent;
ArrayNode pnode = mapper.createArrayNode();
for (Link link : pi.path().links()) {
pnode.add(link.toString());
}
result.set("path", pnode);
} else if (intent instanceof PointToPointIntent) {
PointToPointIntent pi = (PointToPointIntent) intent;
result.set("ingress", LinksListCommand.json(mapper, pi.ingressPoint()));
result.set("egress", LinksListCommand.json(mapper, pi.egressPoint()));
} else if (intent instanceof MultiPointToSinglePointIntent) {
MultiPointToSinglePointIntent pi = (MultiPointToSinglePointIntent) intent;
result.set("ingress", json(mapper, pi.ingressPoints()));
result.set("egress", LinksListCommand.json(mapper, pi.egressPoint()));
} else if (intent instanceof SinglePointToMultiPointIntent) {
SinglePointToMultiPointIntent pi = (SinglePointToMultiPointIntent) intent;
result.set("ingress", LinksListCommand.json(mapper, pi.ingressPoint()));
result.set("egress", json(mapper, pi.egressPoints()));
} else if (intent instanceof LinkCollectionIntent) {
LinkCollectionIntent li = (LinkCollectionIntent) intent;
result.set("links", LinksListCommand.json(li.links()));
}
List<Intent> installable = service.getInstallableIntents(intent.id());
if (installable != null && !installable.isEmpty()) {
result.set("installable", json(service, installable));
}
return result;
}
private JsonNode json(ObjectMapper mapper, Set<ConnectPoint> connectPoints) {
ArrayNode result = mapper.createArrayNode();
for (ConnectPoint cp : connectPoints) {
result.add(LinksListCommand.json(mapper, cp));
}
return result;
}
}
......
......@@ -3,10 +3,11 @@ package org.onlab.onos.cluster;
import java.util.List;
import java.util.Objects;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
/**
* A container for detailed role information for a device,
* An immutable container for role information for a device,
* within the current cluster. Role attributes include current
* master and a preference-ordered list of backup nodes.
*/
......@@ -52,12 +53,9 @@ public class RoleInfo {
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("master:").append(master).append(",");
builder.append("backups:");
for (NodeId n : backups) {
builder.append(" ").append(n);
}
return builder.toString();
return MoreObjects.toStringHelper(this.getClass())
.add("master", master)
.add("backups", backups)
.toString();
}
}
......
package org.onlab.onos.mastership;
import org.onlab.onos.cluster.NodeId;
import org.onlab.onos.cluster.RoleInfo;
import org.onlab.onos.event.AbstractEvent;
import org.onlab.onos.net.DeviceId;
......@@ -9,9 +10,8 @@ import org.onlab.onos.net.DeviceId;
*/
public class MastershipEvent extends AbstractEvent<MastershipEvent.Type, DeviceId> {
//do we worry about explicitly setting slaves/equals? probably not,
//to keep it simple
NodeId node;
//Contains master and standby information.
RoleInfo roleInfo;
/**
* Type of mastership events.
......@@ -29,16 +29,16 @@ public class MastershipEvent extends AbstractEvent<MastershipEvent.Type, DeviceI
}
/**
* Creates an event of a given type and for the specified device, master,
* and the current time.
* Creates an event of a given type and for the specified device,
* role information, and the current time.
*
* @param type device event type
* @param device event device subject
* @param node master ID subject
* @param info mastership role information subject
*/
public MastershipEvent(Type type, DeviceId device, NodeId node) {
public MastershipEvent(Type type, DeviceId device, RoleInfo info) {
super(type, device);
this.node = node;
this.roleInfo = info;
}
/**
......@@ -50,9 +50,9 @@ public class MastershipEvent extends AbstractEvent<MastershipEvent.Type, DeviceI
* @param master master ID subject
* @param time occurrence time
*/
public MastershipEvent(Type type, DeviceId device, NodeId master, long time) {
public MastershipEvent(Type type, DeviceId device, RoleInfo info, long time) {
super(type, device, time);
this.node = master;
this.roleInfo = info;
}
/**
......@@ -63,7 +63,17 @@ public class MastershipEvent extends AbstractEvent<MastershipEvent.Type, DeviceI
*
* @return node ID as a subject
*/
//XXX to-be removed - or keep for convenience?
public NodeId node() {
return node;
return roleInfo.master();
}
/**
* Returns the current role state for the subject.
*
* @return RoleInfo associated with Device ID subject
*/
public RoleInfo roleInfo() {
return roleInfo;
}
}
......
......@@ -27,7 +27,7 @@ public class DefaultFlowEntry extends DefaultFlowRule
TrafficTreatment treatment, int priority, FlowEntryState state,
long life, long packets, long bytes, long flowId,
int timeout) {
super(deviceId, selector, treatment, priority, flowId, timeout);
super(deviceId, selector, treatment, priority, flowId, timeout, false);
this.state = state;
this.life = life;
this.packets = packets;
......
......@@ -24,16 +24,18 @@ public class DefaultFlowRule implements FlowRule {
private final short appId;
private final int timeout;
private final boolean permanent;
public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector,
TrafficTreatment treatment, int priority, long flowId,
int timeout) {
int timeout, boolean permanent) {
this.deviceId = deviceId;
this.priority = priority;
this.selector = selector;
this.treatment = treatment;
this.timeout = timeout;
this.permanent = permanent;
this.created = System.currentTimeMillis();
this.appId = (short) (flowId >>> 48);
......@@ -42,7 +44,7 @@ public class DefaultFlowRule implements FlowRule {
public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector,
TrafficTreatment treatement, int priority, ApplicationId appId,
int timeout) {
int timeout, boolean permanent) {
if (priority < FlowRule.MIN_PRIORITY) {
throw new IllegalArgumentException("Priority cannot be less than " + MIN_PRIORITY);
......@@ -54,6 +56,7 @@ public class DefaultFlowRule implements FlowRule {
this.treatment = treatement;
this.appId = appId.id();
this.timeout = timeout;
this.permanent = permanent;
this.created = System.currentTimeMillis();
this.id = FlowId.valueOf((((long) this.appId) << 48) | (this.hash() & 0x0000ffffffffL));
......@@ -67,6 +70,7 @@ public class DefaultFlowRule implements FlowRule {
this.appId = rule.appId();
this.id = rule.id();
this.timeout = rule.timeout();
this.permanent = rule.isPermanent();
this.created = System.currentTimeMillis();
}
......@@ -157,4 +161,9 @@ public class DefaultFlowRule implements FlowRule {
return timeout;
}
@Override
public boolean isPermanent() {
return permanent;
}
}
......
package org.onlab.onos.net.flow;
import com.google.common.collect.ImmutableSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.flow.criteria.Criteria;
import org.onlab.onos.net.flow.criteria.Criterion;
......@@ -8,10 +12,8 @@ import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableSet;
/**
* Default traffic selector implementation.
......@@ -52,6 +54,13 @@ public final class DefaultTrafficSelector implements TrafficSelector {
return false;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("criteria", criteria)
.toString();
}
/**
* Returns a new traffic selector builder.
*
......
package org.onlab.onos.net.flow;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import org.onlab.onos.net.PortNumber;
import org.onlab.onos.net.flow.instructions.Instruction;
import org.onlab.onos.net.flow.instructions.Instructions;
......@@ -7,12 +11,9 @@ import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
/**
* Default traffic treatment implementation.
*/
......@@ -62,6 +63,13 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
return false;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("instructions", instructions)
.toString();
}
/**
* Builds a list of treatments following the following order.
* Modifications -> Group -> Output (including drop)
......
......@@ -59,8 +59,16 @@ public interface FlowRule extends BatchOperationTarget {
/**
* Returns the timeout for this flow requested by an application.
*
* @return integer value of the timeout
*/
int timeout();
/**
* Returns whether the flow is permanent i.e. does not time out.
*
* @return true if the flow is permanent, otherwise false
*/
boolean isPermanent();
}
......
package org.onlab.onos.net.intent;
import java.util.List;
/**
* Service for application submitting or withdrawing their intents.
*/
......@@ -68,6 +70,15 @@ public interface IntentService {
IntentState getIntentState(IntentId id);
/**
* Returns the list of the installable events associated with the specified
* top-level intent.
*
* @param intentId top-level intent identifier
* @return compiled installable intents
*/
List<Intent> getInstallableIntents(IntentId intentId);
/**
* Adds the specified listener for intent events.
*
* @param listener listener to be added
......
......@@ -196,6 +196,11 @@ public class FakeIntentManager implements TestableIntentService {
}
@Override
public List<Intent> getInstallableIntents(IntentId intentId) {
return installables.get(intentId);
}
@Override
public void addListener(IntentListener listener) {
listeners.add(listener);
}
......
......@@ -327,6 +327,10 @@ public class FlowRuleManager
if (storedRule == null) {
return false;
}
if (storedRule.isPermanent()) {
return true;
}
final long timeout = storedRule.timeout() * 1000;
final long currentTime = System.currentTimeMillis();
if (storedRule.packets() != swRule.packets()) {
......
......@@ -153,6 +153,12 @@ public class IntentManager
}
@Override
public List<Intent> getInstallableIntents(IntentId intentId) {
checkNotNull(intentId, INTENT_ID_NULL);
return store.getInstallableIntents(intentId);
}
@Override
public void addListener(IntentListener listener) {
listenerRegistry.addListener(listener);
}
......
......@@ -117,7 +117,7 @@ public class LinkCollectionIntentInstaller implements IntentInstaller<LinkCollec
TrafficTreatment treatment = builder().setOutput(outPort).build();
FlowRule rule = new DefaultFlowRule(deviceId,
selector, treatment, 123, appId, 600);
selector, treatment, 123, appId, 0, true);
return new FlowRuleBatchEntry(operation, rule);
}
......
......@@ -73,7 +73,7 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
FlowRule rule = new DefaultFlowRule(link.src().deviceId(),
builder.build(), treatment,
123, appId, 15);
123, appId, 0, true);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule));
prev = link.dst();
}
......@@ -95,7 +95,7 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
.setOutput(link.src().port()).build();
FlowRule rule = new DefaultFlowRule(link.src().deviceId(),
builder.build(), treatment,
123, appId, 600);
123, appId, 0, true);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule));
prev = link.dst();
}
......
package org.onlab.onos.net.flow.impl;
import static java.util.Collections.EMPTY_LIST;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_UPDATED;
......@@ -115,7 +119,7 @@ public class FlowRuleManagerTest {
private FlowRule flowRule(int tsval, int trval) {
TestSelector ts = new TestSelector(tsval);
TestTreatment tr = new TestTreatment(trval);
return new DefaultFlowRule(DID, ts, tr, 10, appId, TIMEOUT);
return new DefaultFlowRule(DID, ts, tr, 10, appId, TIMEOUT, false);
}
......
......@@ -5,6 +5,7 @@ import static org.junit.Assert.*;
import java.util.Collections;
import java.util.Map;
import java.util.LinkedList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
......@@ -12,6 +13,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.onos.cluster.NodeId;
import org.onlab.onos.cluster.RoleInfo;
import org.onlab.onos.event.AbstractListenerRegistry;
import org.onlab.onos.event.DefaultEventSinkRegistry;
import org.onlab.onos.event.Event;
......@@ -87,7 +89,8 @@ public class ReplicaInfoManagerTest {
service.addListener(new MasterNodeCheck(latch, DID1, NID1));
// fake MastershipEvent
eventDispatcher.post(new MastershipEvent(Type.MASTER_CHANGED, DID1, NID1));
eventDispatcher.post(new MastershipEvent(Type.MASTER_CHANGED, DID1,
new RoleInfo(NID1, new LinkedList<NodeId>())));
assertTrue(latch.await(1, TimeUnit.SECONDS));
}
......
......@@ -136,13 +136,13 @@ implements MastershipStore {
rv.reassign(nodeId, STANDBY, NONE);
roleMap.put(deviceId, rv);
updateTerm(deviceId);
return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
case NONE:
rv.add(MASTER, nodeId);
rv.reassign(nodeId, STANDBY, NONE);
roleMap.put(deviceId, rv);
updateTerm(deviceId);
return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
default:
log.warn("unknown Mastership Role {}", role);
return null;
......@@ -306,7 +306,7 @@ implements MastershipStore {
roleMap.put(deviceId, rv);
Integer term = terms.get(deviceId);
terms.put(deviceId, ++term);
return new MastershipEvent(MASTER_CHANGED, deviceId, backup);
return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
}
}
......@@ -373,7 +373,7 @@ implements MastershipStore {
return;
}
notifyDelegate(new MastershipEvent(
MASTER_CHANGED, event.getKey(), event.getValue().get(MASTER)));
MASTER_CHANGED, event.getKey(), event.getValue().roleInfo()));
}
@Override
......
......@@ -10,6 +10,9 @@ import org.onlab.onos.cluster.NodeId;
import org.onlab.onos.cluster.RoleInfo;
import org.onlab.onos.net.MastershipRole;
import com.google.common.base.MoreObjects;
import com.google.common.base.MoreObjects.ToStringHelper;
/**
* A structure that holds node mastership roles associated with a
* {@link DeviceId}. This structure needs to be locked through IMap.
......@@ -109,14 +112,10 @@ public class RoleValue {
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
ToStringHelper helper = MoreObjects.toStringHelper(this.getClass());
for (Map.Entry<MastershipRole, List<NodeId>> el : value.entrySet()) {
builder.append(el.getKey().toString()).append(": [");
for (NodeId n : el.getValue()) {
builder.append(n);
}
builder.append("]\n");
helper.add(el.getKey().toString(), el.getValue());
}
return builder.toString();
return helper.toString();
}
}
......
......@@ -29,6 +29,8 @@ import org.onlab.onos.store.AbstractStore;
import org.onlab.packet.IpPrefix;
import org.slf4j.Logger;
import com.google.common.collect.Lists;
import static org.onlab.onos.mastership.MastershipEvent.Type.*;
/**
......@@ -89,7 +91,8 @@ public class SimpleMastershipStore
}
}
return new MastershipEvent(MASTER_CHANGED, deviceId, nodeId);
return new MastershipEvent(MASTER_CHANGED, deviceId,
new RoleInfo(nodeId, Lists.newLinkedList(backups)));
}
@Override
......@@ -196,7 +199,8 @@ public class SimpleMastershipStore
} else {
masterMap.put(deviceId, backup);
termMap.get(deviceId).incrementAndGet();
return new MastershipEvent(MASTER_CHANGED, deviceId, backup);
return new MastershipEvent(MASTER_CHANGED, deviceId,
new RoleInfo(backup, Lists.newLinkedList(backups)));
}
case STANDBY:
case NONE:
......
......@@ -78,7 +78,7 @@ public class FlowEntryBuilder {
if (addedRule) {
FlowRule rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)),
buildSelector(), buildTreatment(), stat.getPriority(),
stat.getCookie().getValue(), stat.getIdleTimeout());
stat.getCookie().getValue(), stat.getIdleTimeout(), false);
return new DefaultFlowEntry(rule, FlowEntryState.ADDED,
stat.getDurationSec(), stat.getPacketCount().getValue(),
stat.getByteCount().getValue());
......@@ -86,7 +86,7 @@ public class FlowEntryBuilder {
} else {
FlowRule rule = new DefaultFlowRule(DeviceId.deviceId(Dpid.uri(dpid)),
buildSelector(), null, removed.getPriority(),
removed.getCookie().getValue(), removed.getIdleTimeout());
removed.getCookie().getValue(), removed.getIdleTimeout(), false);
return new DefaultFlowEntry(rule, FlowEntryState.REMOVED, removed.getDurationSec(),
removed.getPacketCount().getValue(), removed.getByteCount().getValue());
}
......
#!/bin/bash
# -----------------------------------------------------------------------------
# Executes selected set of ONOS commands using the batch mode.
# -----------------------------------------------------------------------------
[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
. $ONOS_ROOT/tools/build/envDefaults
node=${1:-$OCI}
commands="${2:-summary,intents,flows,hosts}"
aux=/tmp/onos-batch.$$
trap "rm -f $aux" EXIT
echo "$commands" | tr ',' '\n' > $aux
onos $node -b <$aux