tom

Reworked intent states to the new set of states.

Separate intent state from intent event type.
Implemented new state transitions in IntentManager.
Implemented ObjectiveTracker.
Re-route now works.
Showing 28 changed files with 296 additions and 304 deletions
......@@ -24,7 +24,7 @@ public class IntentIdCompleter implements Completer {
Iterator<Intent> it = service.getIntents().iterator();
SortedSet<String> strings = delegate.getStrings();
while (it.hasNext()) {
strings.add(it.next().getId().toString());
strings.add(it.next().id().toString());
}
// Now let the completer do the work for figuring out what to offer.
......
......@@ -17,8 +17,8 @@ public class IntentsListCommand extends AbstractShellCommand {
protected void execute() {
IntentService service = get(IntentService.class);
for (Intent intent : service.getIntents()) {
IntentState state = service.getIntentState(intent.getId());
print("%s %s %s", intent.getId(), state, intent);
IntentState state = service.getIntentState(intent.id());
print("%s %s %s", intent.id(), state, intent);
}
}
......
......@@ -34,7 +34,7 @@ public class WipeOutCommand extends ClustersListCommand {
IntentService intentService = get(IntentService.class);
for (Intent intent : intentService.getIntents()) {
if (intentService.getIntentState(intent.getId()) == IntentState.INSTALLED) {
if (intentService.getIntentState(intent.id()) == IntentState.INSTALLED) {
intentService.withdraw(intent);
}
}
......
......@@ -24,7 +24,7 @@ public abstract class AbstractIntent implements Intent {
}
@Override
public IntentId getId() {
public IntentId id() {
return id;
}
......
......@@ -53,7 +53,7 @@ public abstract class ConnectivityIntent extends AbstractIntent {
*
* @return traffic match
*/
public TrafficSelector getTrafficSelector() {
public TrafficSelector selector() {
return selector;
}
......@@ -62,7 +62,7 @@ public abstract class ConnectivityIntent extends AbstractIntent {
*
* @return applied action
*/
public TrafficTreatment getTrafficTreatment() {
public TrafficTreatment treatment() {
return treatment;
}
......
......@@ -80,9 +80,9 @@ public class HostToHostIntent extends ConnectivityIntent {
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("id", getId())
.add("selector", getTrafficSelector())
.add("treatment", getTrafficTreatment())
.add("id", id())
.add("selector", selector())
.add("treatment", treatment())
.add("one", one)
.add("two", two)
.toString();
......
......@@ -11,5 +11,5 @@ public interface Intent extends BatchOperationTarget {
*
* @return intent identifier
*/
IntentId getId();
IntentId id();
}
......
package org.onlab.onos.net.intent;
import com.google.common.base.MoreObjects;
import org.onlab.onos.event.AbstractEvent;
import java.util.Objects;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A class to represent an intent related event.
*/
public class IntentEvent extends AbstractEvent<IntentState, Intent> {
// TODO: determine a suitable parent class; if one does not exist, consider
// introducing one
public class IntentEvent extends AbstractEvent<IntentEvent.Type, Intent> {
private final long time;
private final Intent intent;
private final IntentState state;
private final IntentState previous;
public enum Type {
/**
* Signifies that a new intent has been submitted to the system.
*/
SUBMITTED,
/**
* Creates an event describing a state change of an intent.
*
* @param intent subject intent
* @param state new intent state
* @param previous previous intent state
* @param time time the event created in milliseconds since start of epoch
* @throws NullPointerException if the intent or state is null
* Signifies that an intent has been successfully installed.
*/
public IntentEvent(Intent intent, IntentState state, IntentState previous, long time) {
super(state, intent);
this.intent = checkNotNull(intent);
this.state = checkNotNull(state);
this.previous = previous;
this.time = time;
}
INSTALLED,
/**
* Returns the state of the intent which caused the event.
*
* @return the state of the intent
* Signifies that an intent has failed compilation or installation.
*/
public IntentState getState() {
return state;
}
FAILED,
/**
* Returns the previous state of the intent which caused the event.
*
* @return the previous state of the intent
* Signifies that an intent has been withdrawn from the system.
*/
public IntentState getPreviousState() {
return previous;
WITHDRAWN
}
/**
* Returns the intent associated with the event.
* Creates an event of a given type and for the specified intent and the
* current time.
*
* @return the intent
* @param type event type
* @param intent subject intent
* @param time time the event created in milliseconds since start of epoch
*/
public Intent getIntent() {
return intent;
public IntentEvent(Type type, Intent intent, long time) {
super(type, intent, time);
}
/**
* Returns the time at which the event was created.
* Creates an event of a given type and for the specified intent and the
* current time.
*
* @return the time in milliseconds since start of epoch
* @param type event type
* @param intent subject intent
*/
public long getTime() {
return time;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
public IntentEvent(Type type, Intent intent) {
super(type, intent);
}
IntentEvent that = (IntentEvent) o;
return Objects.equals(this.intent, that.intent)
&& Objects.equals(this.state, that.state)
&& Objects.equals(this.previous, that.previous)
&& Objects.equals(this.time, that.time);
}
@Override
public int hashCode() {
return Objects.hash(intent, state, previous, time);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("intent", intent)
.add("state", state)
.add("previous", previous)
.add("time", time)
.toString();
}
}
......
package org.onlab.onos.net.intent;
/**
* This class represents the states of an intent.
*
* <p>
* Note: The state is expressed as enum, but there is possibility
* in the future that we define specific class instead of enum to improve
* the extensibility of state definition.
* </p>
* Representation of the phases an intent may attain during its lifecycle.
*/
public enum IntentState {
// FIXME: requires discussion on State vs. EventType and a solid state-transition diagram
// TODO: consider the impact of conflict detection
// TODO: consider the impact that external events affect an installed intent
/**
* The beginning state.
*
* Signifies that the intent has been submitted and will start compiling
* shortly. However, this compilation may not necessarily occur on the
* local controller instance.
* <p/>
* All intent in the runtime take this state first.
*/
SUBMITTED,
/**
* The intent compilation has been completed.
*
* An intent translation graph (tree) is completely created.
* Leaves of the graph are installable intent type.
* Signifies that the intent is being compiled into installable intents.
* This is a transitional state after which the intent will enter either
* {@link #FAILED} state or {@link #INSTALLING} state.
*/
COMPILING,
/**
* Signifies that the resulting installable intents are being installed
* into the network environment. This is a transitional state after which
* the intent will enter either {@link #INSTALLED} state or
* {@link #RECOMPILING} state.
*/
COMPILED,
INSTALLING,
/**
* The intent has been successfully installed.
* The intent has been successfully installed. This is a state where the
* intent may remain parked until it is withdrawn by the application or
* until the network environment changes in some way to make the original
* set of installable intents untenable.
*/
INSTALLED,
/**
* The intent is being withdrawn.
*
* When {@link IntentService#withdraw(Intent)} is called,
* the intent takes this state first.
* Signifies that the intent is being recompiled into installable intents
* as an attempt to adapt to an anomaly in the network environment.
* This is a transitional state after which the intent will enter either
* {@link #FAILED} state or {@link #INSTALLING} state.
* <p/>
* Exit to the {@link #FAILED} state may be caused by failure to compile
* or by compiling into the same set of installable intents which have
* previously failed to be installed.
*/
RECOMPILING,
/**
* Indicates that the intent is being withdrawn. This is a transitional
* state, triggered by invocation of the
* {@link IntentService#withdraw(Intent)} but one with only one outcome,
* which is the the intent being placed in the {@link #WITHDRAWN} state.
*/
WITHDRAWING,
/**
* The intent has been successfully withdrawn.
* Indicates that the intent has been successfully withdrawn.
*/
WITHDRAWN,
/**
* The intent has failed to be compiled, installed, or withdrawn.
*
* When the intent failed to be withdrawn, it is still, at least partially installed.
* Signifies that the intent has failed compiling, installing or
* recompiling states.
*/
FAILED,
FAILED
}
......
......@@ -10,10 +10,16 @@ import java.util.List;
public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> {
/**
* Creates a new intent.
* Submits a new intent into the store. If the returned event is not
* null, the manager is expected to dispatch the event and then to kick
* off intent compilation process. Otherwise, another node has been elected
* to perform the compilation process and the node will learn about
* the submittal and results of the intent compilation via the delegate
* mechanism.
*
* @param intent intent
* @return appropriate event or null if no change resulted
* @param intent intent to be submitted
* @return event indicating the intent was submitted or null if no
* change resulted, e.g. duplicate intent
*/
IntentEvent createIntent(Intent intent);
......@@ -68,9 +74,8 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> {
*
* @param intentId original intent identifier
* @param installableIntents compiled installable intents
* @return compiled state transition event
*/
IntentEvent addInstallableIntents(IntentId intentId,
void addInstallableIntents(IntentId intentId,
List<InstallableIntent> installableIntents);
/**
......
package org.onlab.onos.net.intent;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Objects;
import java.util.Set;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Sets;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Sets;
import java.util.Objects;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Abstraction of multiple source to single destination connectivity intent.
*/
public class MultiPointToSinglePointIntent extends ConnectivityIntent {
private final Set<ConnectPoint> ingressPorts;
private final ConnectPoint egressPort;
private final Set<ConnectPoint> ingressPoints;
private final ConnectPoint egressPoint;
/**
* Creates a new multi-to-single point connectivity intent for the specified
......@@ -28,25 +27,25 @@ public class MultiPointToSinglePointIntent extends ConnectivityIntent {
* @param id intent identifier
* @param match traffic match
* @param action action
* @param ingressPorts set of ports from which ingress traffic originates
* @param egressPort port to which traffic will egress
* @throws NullPointerException if {@code ingressPorts} or
* {@code egressPort} is null.
* @throws IllegalArgumentException if the size of {@code ingressPorts} is
* @param ingressPoints set of ports from which ingress traffic originates
* @param egressPoint port to which traffic will egress
* @throws NullPointerException if {@code ingressPoints} or
* {@code egressPoint} is null.
* @throws IllegalArgumentException if the size of {@code ingressPoints} is
* not more than 1
*/
public MultiPointToSinglePointIntent(IntentId id, TrafficSelector match,
TrafficTreatment action,
Set<ConnectPoint> ingressPorts,
ConnectPoint egressPort) {
Set<ConnectPoint> ingressPoints,
ConnectPoint egressPoint) {
super(id, match, action);
checkNotNull(ingressPorts);
checkArgument(!ingressPorts.isEmpty(),
checkNotNull(ingressPoints);
checkArgument(!ingressPoints.isEmpty(),
"there should be at least one ingress port");
this.ingressPorts = Sets.newHashSet(ingressPorts);
this.egressPort = checkNotNull(egressPort);
this.ingressPoints = Sets.newHashSet(ingressPoints);
this.egressPoint = checkNotNull(egressPoint);
}
/**
......@@ -54,8 +53,8 @@ public class MultiPointToSinglePointIntent extends ConnectivityIntent {
*/
protected MultiPointToSinglePointIntent() {
super();
this.ingressPorts = null;
this.egressPort = null;
this.ingressPoints = null;
this.egressPoint = null;
}
/**
......@@ -64,8 +63,8 @@ public class MultiPointToSinglePointIntent extends ConnectivityIntent {
*
* @return set of ingress ports
*/
public Set<ConnectPoint> getIngressPorts() {
return ingressPorts;
public Set<ConnectPoint> ingressPoints() {
return ingressPoints;
}
/**
......@@ -73,8 +72,8 @@ public class MultiPointToSinglePointIntent extends ConnectivityIntent {
*
* @return egress port
*/
public ConnectPoint getEgressPort() {
return egressPort;
public ConnectPoint egressPoint() {
return egressPoint;
}
@Override
......@@ -90,23 +89,23 @@ public class MultiPointToSinglePointIntent extends ConnectivityIntent {
}
MultiPointToSinglePointIntent that = (MultiPointToSinglePointIntent) o;
return Objects.equals(this.ingressPorts, that.ingressPorts)
&& Objects.equals(this.egressPort, that.egressPort);
return Objects.equals(this.ingressPoints, that.ingressPoints)
&& Objects.equals(this.egressPoint, that.egressPoint);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), ingressPorts, egressPort);
return Objects.hash(super.hashCode(), ingressPoints, egressPoint);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("id", getId())
.add("match", getTrafficSelector())
.add("action", getTrafficTreatment())
.add("ingressPorts", getIngressPorts())
.add("egressPort", getEgressPort())
.add("id", id())
.add("match", selector())
.add("action", treatment())
.add("ingressPoints", ingressPoints())
.add("egressPoint", egressPoint())
.toString();
}
}
......
......@@ -46,7 +46,7 @@ public class PathIntent extends PointToPointIntent implements InstallableIntent
*
* @return traversed links
*/
public Path getPath() {
public Path path() {
return path;
}
......@@ -79,11 +79,11 @@ public class PathIntent extends PointToPointIntent implements InstallableIntent
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("id", getId())
.add("match", getTrafficSelector())
.add("action", getTrafficTreatment())
.add("ingressPort", getIngressPort())
.add("egressPort", getEgressPort())
.add("id", id())
.add("match", selector())
.add("action", treatment())
.add("ingressPort", ingressPoint())
.add("egressPort", egressPoint())
.add("path", path)
.toString();
}
......
......@@ -14,8 +14,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public class PointToPointIntent extends ConnectivityIntent {
private final ConnectPoint ingressPort;
private final ConnectPoint egressPort;
private final ConnectPoint ingressPoint;
private final ConnectPoint egressPoint;
/**
* Creates a new point-to-point intent with the supplied ingress/egress
......@@ -24,17 +24,17 @@ public class PointToPointIntent extends ConnectivityIntent {
* @param id intent identifier
* @param selector traffic selector
* @param treatment treatment
* @param ingressPort ingress port
* @param egressPort egress port
* @throws NullPointerException if {@code ingressPort} or {@code egressPort} is null.
* @param ingressPoint ingress port
* @param egressPoint egress port
* @throws NullPointerException if {@code ingressPoint} or {@code egressPoints} is null.
*/
public PointToPointIntent(IntentId id, TrafficSelector selector,
TrafficTreatment treatment,
ConnectPoint ingressPort,
ConnectPoint egressPort) {
ConnectPoint ingressPoint,
ConnectPoint egressPoint) {
super(id, selector, treatment);
this.ingressPort = checkNotNull(ingressPort);
this.egressPort = checkNotNull(egressPort);
this.ingressPoint = checkNotNull(ingressPoint);
this.egressPoint = checkNotNull(egressPoint);
}
/**
......@@ -42,8 +42,8 @@ public class PointToPointIntent extends ConnectivityIntent {
*/
protected PointToPointIntent() {
super();
this.ingressPort = null;
this.egressPort = null;
this.ingressPoint = null;
this.egressPoint = null;
}
/**
......@@ -52,8 +52,8 @@ public class PointToPointIntent extends ConnectivityIntent {
*
* @return ingress port
*/
public ConnectPoint getIngressPort() {
return ingressPort;
public ConnectPoint ingressPoint() {
return ingressPoint;
}
/**
......@@ -61,8 +61,8 @@ public class PointToPointIntent extends ConnectivityIntent {
*
* @return egress port
*/
public ConnectPoint getEgressPort() {
return egressPort;
public ConnectPoint egressPoint() {
return egressPoint;
}
@Override
......@@ -78,23 +78,23 @@ public class PointToPointIntent extends ConnectivityIntent {
}
PointToPointIntent that = (PointToPointIntent) o;
return Objects.equals(this.ingressPort, that.ingressPort)
&& Objects.equals(this.egressPort, that.egressPort);
return Objects.equals(this.ingressPoint, that.ingressPoint)
&& Objects.equals(this.egressPoint, that.egressPoint);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), ingressPort, egressPort);
return Objects.hash(super.hashCode(), ingressPoint, egressPoint);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("id", getId())
.add("match", getTrafficSelector())
.add("action", getTrafficTreatment())
.add("ingressPort", ingressPort)
.add("egressPort", egressPort)
.add("id", id())
.add("match", selector())
.add("action", treatment())
.add("ingressPoint", ingressPoint)
.add("egressPoints", egressPoint)
.toString();
}
......
......@@ -17,8 +17,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public class SinglePointToMultiPointIntent extends ConnectivityIntent {
private final ConnectPoint ingressPort;
private final Set<ConnectPoint> egressPorts;
private final ConnectPoint ingressPoint;
private final Set<ConnectPoint> egressPoints;
/**
* Creates a new single-to-multi point connectivity intent.
......@@ -26,25 +26,25 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent {
* @param id intent identifier
* @param selector traffic selector
* @param treatment treatment
* @param ingressPort port on which traffic will ingress
* @param egressPorts set of ports on which traffic will egress
* @throws NullPointerException if {@code ingressPort} or
* {@code egressPorts} is null
* @throws IllegalArgumentException if the size of {@code egressPorts} is
* @param ingressPoint port on which traffic will ingress
* @param egressPoints set of ports on which traffic will egress
* @throws NullPointerException if {@code ingressPoint} or
* {@code egressPoints} is null
* @throws IllegalArgumentException if the size of {@code egressPoints} is
* not more than 1
*/
public SinglePointToMultiPointIntent(IntentId id, TrafficSelector selector,
TrafficTreatment treatment,
ConnectPoint ingressPort,
Set<ConnectPoint> egressPorts) {
ConnectPoint ingressPoint,
Set<ConnectPoint> egressPoints) {
super(id, selector, treatment);
checkNotNull(egressPorts);
checkArgument(!egressPorts.isEmpty(),
checkNotNull(egressPoints);
checkArgument(!egressPoints.isEmpty(),
"there should be at least one egress port");
this.ingressPort = checkNotNull(ingressPort);
this.egressPorts = Sets.newHashSet(egressPorts);
this.ingressPoint = checkNotNull(ingressPoint);
this.egressPoints = Sets.newHashSet(egressPoints);
}
/**
......@@ -52,8 +52,8 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent {
*/
protected SinglePointToMultiPointIntent() {
super();
this.ingressPort = null;
this.egressPorts = null;
this.ingressPoint = null;
this.egressPoints = null;
}
/**
......@@ -61,8 +61,8 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent {
*
* @return ingress port
*/
public ConnectPoint getIngressPort() {
return ingressPort;
public ConnectPoint ingressPoint() {
return ingressPoint;
}
/**
......@@ -70,8 +70,8 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent {
*
* @return set of egress ports
*/
public Set<ConnectPoint> getEgressPorts() {
return egressPorts;
public Set<ConnectPoint> egressPoints() {
return egressPoints;
}
@Override
......@@ -87,23 +87,23 @@ public class SinglePointToMultiPointIntent extends ConnectivityIntent {
}
SinglePointToMultiPointIntent that = (SinglePointToMultiPointIntent) o;
return Objects.equals(this.ingressPort, that.ingressPort)
&& Objects.equals(this.egressPorts, that.egressPorts);
return Objects.equals(this.ingressPoint, that.ingressPoint)
&& Objects.equals(this.egressPoints, that.egressPoints);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), ingressPort, egressPorts);
return Objects.hash(super.hashCode(), ingressPoint, egressPoints);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("id", getId())
.add("match", getTrafficSelector())
.add("action", getTrafficTreatment())
.add("ingressPort", ingressPort)
.add("egressPort", egressPorts)
.add("id", id())
.add("match", selector())
.add("action", treatment())
.add("ingressPoint", ingressPoint)
.add("egressPort", egressPoints)
.toString();
}
......
......@@ -40,8 +40,7 @@ public class FakeIntentManager implements TestableIntentService {
@Override
public void run() {
try {
List<InstallableIntent> installable = compileIntent(intent);
installIntents(intent, installable);
executeCompilingPhase(intent);
} catch (IntentException e) {
exceptions.add(e);
}
......@@ -55,8 +54,8 @@ public class FakeIntentManager implements TestableIntentService {
@Override
public void run() {
try {
List<InstallableIntent> installable = getInstallable(intent.getId());
uninstallIntents(intent, installable);
List<InstallableIntent> installable = getInstallable(intent.id());
executeWithdrawingPhase(intent, installable);
} catch (IntentException e) {
exceptions.add(e);
}
......@@ -84,53 +83,60 @@ public class FakeIntentManager implements TestableIntentService {
return installer;
}
private <T extends Intent> List<InstallableIntent> compileIntent(T intent) {
private <T extends Intent> void executeCompilingPhase(T intent) {
setState(intent, IntentState.COMPILING);
try {
// For the fake, we compile using a single level pass
List<InstallableIntent> installable = new ArrayList<>();
for (Intent compiled : getCompiler(intent).compile(intent)) {
installable.add((InstallableIntent) compiled);
}
setState(intent, IntentState.COMPILED);
return installable;
executeInstallingPhase(intent, installable);
} catch (IntentException e) {
setState(intent, IntentState.FAILED);
throw e;
dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
}
}
private void installIntents(Intent intent, List<InstallableIntent> installable) {
private void executeInstallingPhase(Intent intent,
List<InstallableIntent> installable) {
setState(intent, IntentState.INSTALLING);
try {
for (InstallableIntent ii : installable) {
registerSubclassInstallerIfNeeded(ii);
getInstaller(ii).install(ii);
}
setState(intent, IntentState.INSTALLED);
putInstallable(intent.getId(), installable);
putInstallable(intent.id(), installable);
dispatch(new IntentEvent(IntentEvent.Type.INSTALLED, intent));
} catch (IntentException e) {
setState(intent, IntentState.FAILED);
throw e;
dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
}
}
private void uninstallIntents(Intent intent, List<InstallableIntent> installable) {
private void executeWithdrawingPhase(Intent intent,
List<InstallableIntent> installable) {
setState(intent, IntentState.WITHDRAWING);
try {
for (InstallableIntent ii : installable) {
getInstaller(ii).uninstall(ii);
}
removeInstallable(intent.id());
setState(intent, IntentState.WITHDRAWN);
removeInstallable(intent.getId());
dispatch(new IntentEvent(IntentEvent.Type.WITHDRAWN, intent));
} catch (IntentException e) {
// FIXME: Do we really want to do this?
setState(intent, IntentState.FAILED);
throw e;
dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent));
}
}
// Sets the internal state for the given intent and dispatches an event
private void setState(Intent intent, IntentState state) {
IntentState previous = intentStates.get(intent.getId());
intentStates.put(intent.getId(), state);
dispatch(new IntentEvent(intent, state, previous, System.currentTimeMillis()));
intentStates.put(intent.id(), state);
}
private void putInstallable(IntentId id, List<InstallableIntent> installable) {
......@@ -152,15 +158,15 @@ public class FakeIntentManager implements TestableIntentService {
@Override
public void submit(Intent intent) {
intents.put(intent.getId(), intent);
intents.put(intent.id(), intent);
setState(intent, IntentState.SUBMITTED);
dispatch(new IntentEvent(IntentEvent.Type.SUBMITTED, intent));
executeSubmit(intent);
}
@Override
public void withdraw(Intent intent) {
intents.remove(intent.getId());
setState(intent, IntentState.WITHDRAWING);
intents.remove(intent.id());
executeWithdraw(intent);
}
......
......@@ -10,11 +10,9 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import static org.onlab.onos.net.intent.IntentState.*;
import static org.junit.Assert.*;
import static org.onlab.onos.net.intent.IntentEvent.Type.*;
// TODO: consider make it categorized as integration test when it become
// slow test or fragile test
/**
* Suite of tests for the intent service contract.
*/
......@@ -64,13 +62,13 @@ public class IntentServiceTest {
TestTools.assertAfter(GRACE_MS, new Runnable() {
@Override
public void run() {
assertEquals("incorrect intent state", INSTALLED,
service.getIntentState(intent.getId()));
assertEquals("incorrect intent state", IntentState.INSTALLED,
service.getIntentState(intent.id()));
}
});
// Make sure that all expected events have been emitted
validateEvents(intent, SUBMITTED, COMPILED, INSTALLED);
validateEvents(intent, SUBMITTED, INSTALLED);
// Make sure there is just one intent (and is ours)
assertEquals("incorrect intent count", 1, service.getIntentCount());
......@@ -85,19 +83,19 @@ public class IntentServiceTest {
TestTools.assertAfter(GRACE_MS, new Runnable() {
@Override
public void run() {
assertEquals("incorrect intent state", WITHDRAWN,
service.getIntentState(intent.getId()));
assertEquals("incorrect intent state", IntentState.WITHDRAWN,
service.getIntentState(intent.id()));
}
});
// Make sure that all expected events have been emitted
validateEvents(intent, WITHDRAWING, WITHDRAWN);
validateEvents(intent, WITHDRAWN);
// TODO: discuss what is the fate of intents after they have been withdrawn
// Make sure that the intent is no longer in the system
// assertEquals("incorrect intent count", 0, service.getIntents().size());
// assertNull("intent should not be found", service.getIntent(intent.getId()));
// assertNull("intent state should not be found", service.getIntentState(intent.getId()));
// assertNull("intent should not be found", service.getIntent(intent.id()));
// assertNull("intent state should not be found", service.getIntentState(intent.id()));
}
@Test
......@@ -113,8 +111,8 @@ public class IntentServiceTest {
TestTools.assertAfter(GRACE_MS, new Runnable() {
@Override
public void run() {
assertEquals("incorrect intent state", FAILED,
service.getIntentState(intent.getId()));
assertEquals("incorrect intent state", IntentState.FAILED,
service.getIntentState(intent.id()));
}
});
......@@ -136,13 +134,13 @@ public class IntentServiceTest {
TestTools.assertAfter(GRACE_MS, new Runnable() {
@Override
public void run() {
assertEquals("incorrect intent state", FAILED,
service.getIntentState(intent.getId()));
assertEquals("incorrect intent state", IntentState.FAILED,
service.getIntentState(intent.id()));
}
});
// Make sure that all expected events have been emitted
validateEvents(intent, SUBMITTED, COMPILED, FAILED);
validateEvents(intent, SUBMITTED, FAILED);
}
/**
......@@ -151,23 +149,23 @@ public class IntentServiceTest {
* considered.
*
* @param intent intent subject
* @param states list of states for which events are expected
* @param types list of event types for which events are expected
*/
protected void validateEvents(Intent intent, IntentState... states) {
protected void validateEvents(Intent intent, IntentEvent.Type... types) {
Iterator<IntentEvent> events = listener.events.iterator();
for (IntentState state : states) {
for (IntentEvent.Type type : types) {
IntentEvent event = events.hasNext() ? events.next() : null;
if (event == null) {
fail("expected event not found: " + state);
} else if (intent.equals(event.getIntent())) {
assertEquals("incorrect state", state, event.getState());
fail("expected event not found: " + type);
} else if (intent.equals(event.subject())) {
assertEquals("incorrect state", type, event.type());
}
}
// Remainder of events should not apply to this intent; make sure.
while (events.hasNext()) {
assertFalse("unexpected event for intent",
intent.equals(events.next().getIntent()));
intent.equals(events.next().subject()));
}
}
......@@ -228,8 +226,8 @@ public class IntentServiceTest {
TestTools.assertAfter(GRACE_MS, new Runnable() {
@Override
public void run() {
assertEquals("incorrect intent state", INSTALLED,
service.getIntentState(intent.getId()));
assertEquals("incorrect intent state", IntentState.INSTALLED,
service.getIntentState(intent.id()));
}
});
......
......@@ -12,10 +12,10 @@ public class MultiPointToSinglePointIntentTest extends ConnectivityIntentTest {
@Test
public void basics() {
MultiPointToSinglePointIntent intent = createOne();
assertEquals("incorrect id", IID, intent.getId());
assertEquals("incorrect match", MATCH, intent.getTrafficSelector());
assertEquals("incorrect ingress", PS1, intent.getIngressPorts());
assertEquals("incorrect egress", P2, intent.getEgressPort());
assertEquals("incorrect id", IID, intent.id());
assertEquals("incorrect match", MATCH, intent.selector());
assertEquals("incorrect ingress", PS1, intent.ingressPoints());
assertEquals("incorrect egress", P2, intent.egressPoint());
}
@Override
......
......@@ -16,12 +16,12 @@ public class PathIntentTest extends ConnectivityIntentTest {
@Test
public void basics() {
PathIntent intent = createOne();
assertEquals("incorrect id", IID, intent.getId());
assertEquals("incorrect match", MATCH, intent.getTrafficSelector());
assertEquals("incorrect action", NOP, intent.getTrafficTreatment());
assertEquals("incorrect ingress", P1, intent.getIngressPort());
assertEquals("incorrect egress", P2, intent.getEgressPort());
assertEquals("incorrect path", PATH1, intent.getPath());
assertEquals("incorrect id", IID, intent.id());
assertEquals("incorrect match", MATCH, intent.selector());
assertEquals("incorrect action", NOP, intent.treatment());
assertEquals("incorrect ingress", P1, intent.ingressPoint());
assertEquals("incorrect egress", P2, intent.egressPoint());
assertEquals("incorrect path", PATH1, intent.path());
}
@Override
......
......@@ -12,10 +12,10 @@ public class PointToPointIntentTest extends ConnectivityIntentTest {
@Test
public void basics() {
PointToPointIntent intent = createOne();
assertEquals("incorrect id", IID, intent.getId());
assertEquals("incorrect match", MATCH, intent.getTrafficSelector());
assertEquals("incorrect ingress", P1, intent.getIngressPort());
assertEquals("incorrect egress", P2, intent.getEgressPort());
assertEquals("incorrect id", IID, intent.id());
assertEquals("incorrect match", MATCH, intent.selector());
assertEquals("incorrect ingress", P1, intent.ingressPoint());
assertEquals("incorrect egress", P2, intent.egressPoint());
}
@Override
......
......@@ -12,10 +12,10 @@ public class SinglePointToMultiPointIntentTest extends ConnectivityIntentTest {
@Test
public void basics() {
SinglePointToMultiPointIntent intent = createOne();
assertEquals("incorrect id", IID, intent.getId());
assertEquals("incorrect match", MATCH, intent.getTrafficSelector());
assertEquals("incorrect ingress", P1, intent.getIngressPort());
assertEquals("incorrect egress", PS2, intent.getEgressPorts());
assertEquals("incorrect id", IID, intent.id());
assertEquals("incorrect match", MATCH, intent.selector());
assertEquals("incorrect ingress", P1, intent.ingressPoint());
assertEquals("incorrect egress", PS2, intent.egressPoints());
}
@Override
......
......@@ -71,11 +71,11 @@ public class HostToHostIntentCompiler
private Intent createPathIntent(Path path, Host src, Host dst,
HostToHostIntent intent) {
TrafficSelector selector = builder(intent.getTrafficSelector())
TrafficSelector selector = builder(intent.selector())
.matchEthSrc(src.mac()).matchEthDst(dst.mac()).build();
return new PathIntent(intentIdGenerator.getNewId(),
selector, intent.getTrafficTreatment(),
selector, intent.treatment(),
path.src(), path.dst(), path);
}
......
......@@ -19,12 +19,15 @@ import org.onlab.onos.net.topology.TopologyService;
import org.slf4j.Logger;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Multimaps.synchronizedSetMultimap;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED;
import static org.onlab.util.Tools.namedThreads;
import static org.slf4j.LoggerFactory.getLogger;
......@@ -34,7 +37,7 @@ import static org.slf4j.LoggerFactory.getLogger;
*/
@Component
@Service
public class FlowTracker implements FlowTrackerService {
public class ObjectiveTracker implements ObjectiveTrackerService {
private final Logger log = getLogger(getClass());
......@@ -110,15 +113,27 @@ public class FlowTracker implements FlowTrackerService {
@Override
public void run() {
if (event.reasons() == null) {
delegate.bumpIntents(intentsByLink.values());
delegate.triggerCompile(null, false);
} else {
Set<IntentId> toBeRecompiled = new HashSet<>();
boolean recompileOnly = true;
// Scan through the list of reasons and keep accruing all
// intents that need to be recompiled.
for (Event reason : event.reasons()) {
if (reason instanceof LinkEvent) {
LinkEvent linkEvent = (LinkEvent) reason;
delegate.bumpIntents(intentsByLink.get(new LinkKey(linkEvent.subject())));
if (linkEvent.type() == LINK_REMOVED) {
Set<IntentId> intentIds = intentsByLink.get(new LinkKey(linkEvent.subject()));
toBeRecompiled.addAll(intentIds);
}
recompileOnly = recompileOnly && linkEvent.type() == LINK_REMOVED;
}
}
delegate.triggerCompile(toBeRecompiled, !recompileOnly);
}
}
}
......
......@@ -9,7 +9,7 @@ import java.util.Collection;
* Auxiliary service for tracking intent path flows and for notifying the
* intent service of environment changes via topology change delegate.
*/
public interface FlowTrackerService {
public interface ObjectiveTrackerService {
/**
* Sets a topology change delegate.
......
......@@ -49,8 +49,8 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
@Override
public void install(PathIntent intent) {
TrafficSelector.Builder builder =
DefaultTrafficSelector.builder(intent.getTrafficSelector());
Iterator<Link> links = intent.getPath().links().iterator();
DefaultTrafficSelector.builder(intent.selector());
Iterator<Link> links = intent.path().links().iterator();
ConnectPoint prev = links.next().dst();
while (links.hasNext()) {
......@@ -70,8 +70,8 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
@Override
public void uninstall(PathIntent intent) {
TrafficSelector.Builder builder =
DefaultTrafficSelector.builder(intent.getTrafficSelector());
Iterator<Link> links = intent.getPath().links().iterator();
DefaultTrafficSelector.builder(intent.selector());
Iterator<Link> links = intent.path().links().iterator();
ConnectPoint prev = links.next().dst();
while (links.hasNext()) {
......
......@@ -9,10 +9,14 @@ public interface TopologyChangeDelegate {
/**
* Notifies that topology has changed in such a way that the specified
* intents should be recompiled.
* intents should be recompiled. If the {@code compileAllFailed} parameter
* is true, the all intents in {@link org.onlab.onos.net.intent.IntentState#FAILED}
* state should be compiled as well.
*
* @param intentIds intents that should be recompiled
* @param compileAllFailed true implies full compile is required; false for
* selective recompile only
*/
void bumpIntents(Iterable<IntentId> intentIds);
void triggerCompile(Iterable<IntentId> intentIds, boolean compileAllFailed);
}
......
package org.onlab.onos.store.trivial.impl;
import static org.onlab.onos.net.intent.IntentState.COMPILED;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.common.collect.ImmutableSet;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -21,7 +15,12 @@ import org.onlab.onos.net.intent.IntentStoreDelegate;
import org.onlab.onos.store.AbstractStore;
import org.slf4j.Logger;
import com.google.common.collect.ImmutableSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.onlab.onos.net.intent.IntentState.*;
import static org.slf4j.LoggerFactory.getLogger;
@Component(immediate = true)
@Service
......@@ -46,7 +45,7 @@ public class SimpleIntentStore
@Override
public IntentEvent createIntent(Intent intent) {
intents.put(intent.getId(), intent);
intents.put(intent.id(), intent);
return this.setState(intent, IntentState.SUBMITTED);
}
......@@ -54,7 +53,7 @@ public class SimpleIntentStore
public IntentEvent removeIntent(IntentId intentId) {
Intent intent = intents.remove(intentId);
installable.remove(intentId);
IntentEvent event = this.setState(intent, IntentState.WITHDRAWN);
IntentEvent event = this.setState(intent, WITHDRAWN);
states.remove(intentId);
return event;
}
......@@ -79,19 +78,21 @@ public class SimpleIntentStore
return states.get(id);
}
// TODO return dispatch event here... replace with state transition methods
@Override
public IntentEvent setState(Intent intent, IntentState newState) {
IntentId id = intent.getId();
IntentState oldState = states.get(id);
states.put(id, newState);
return new IntentEvent(intent, newState, oldState, System.currentTimeMillis());
public IntentEvent setState(Intent intent, IntentState state) {
IntentId id = intent.id();
states.put(id, state);
IntentEvent.Type type = (state == SUBMITTED ? IntentEvent.Type.SUBMITTED :
(state == INSTALLED ? IntentEvent.Type.INSTALLED :
(state == FAILED ? IntentEvent.Type.FAILED :
state == WITHDRAWN ? IntentEvent.Type.WITHDRAWN :
null)));
return type == null ? null : new IntentEvent(type, intent);
}
@Override
public IntentEvent addInstallableIntents(IntentId intentId, List<InstallableIntent> result) {
public void addInstallableIntents(IntentId intentId, List<InstallableIntent> result) {
installable.put(intentId, result);
return this.setState(intents.get(intentId), COMPILED);
}
@Override
......
......@@ -89,5 +89,5 @@ function spy {
}
function nuke {
spy | cut -c7-11 | xargs kill
spy "$@" | cut -c7-11 | xargs kill
}
......