Brian O'Connor
Committed by Gerrit Code Review

Refactored intent framework to deal with batches.

There is still work to be done, but for now, submit, withdraw and reroute are working.

Change-Id: Ib94cf8c4be03786cc070f402d1f296f5dfa6588b
Showing 27 changed files with 824 additions and 247 deletions
......@@ -29,6 +29,7 @@ import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentEvent;
import org.onlab.onos.net.intent.IntentEvent.Type;
import org.onlab.onos.net.intent.IntentListener;
import org.onlab.onos.net.intent.IntentOperations;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.net.intent.PointToPointIntent;
import org.onlab.packet.Ethernet;
......@@ -63,9 +64,6 @@ public class IntentPushTestCommand extends AbstractShellCommand
required = true, multiValued = false)
String countString = null;
private static long id = 0x7870001;
private IntentService service;
private CountDownLatch latch;
private long start, end;
......@@ -91,15 +89,18 @@ public class IntentPushTestCommand extends AbstractShellCommand
service.addListener(this);
latch = new CountDownLatch(count);
start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
IntentOperations.Builder ops = IntentOperations.builder();
for (int i = 1; i <= count; i++) {
TrafficSelector s = selector
.matchEthSrc(MacAddress.valueOf(i))
.build();
Intent intent = new PointToPointIntent(appId(), s, treatment,
ingress, egress);
service.submit(intent);
ops.addSubmitOperation(intent);
}
IntentOperations operations = ops.build();
start = System.currentTimeMillis();
service.execute(operations);
try {
if (latch.await(10, TimeUnit.SECONDS)) {
printResults(count);
......
......@@ -15,13 +15,13 @@
*/
package org.onlab.onos.net.flow;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A list of BatchOperationEntry.
*
......@@ -88,6 +88,16 @@ public abstract class BatchOperation<T extends BatchOperationEntry<?, ?>> {
return ops.add(entry) ? this : null;
}
/**
* Add all operations from another batch to this batch.
*
* @param another another batch
* @return true if success
*/
public boolean addAll(BatchOperation<T> another) {
return ops.addAll(another.getOperations());
}
@Override
public boolean equals(Object o) {
if (this == o) {
......
......@@ -19,12 +19,20 @@ import java.util.Set;
import com.google.common.collect.ImmutableSet;
/**
* Representation of a completed flow rule batch operation.
*/
public class CompletedBatchOperation implements BatchOperationResult<FlowRule> {
private final boolean success;
private final Set<FlowRule> failures;
/**
* Creates a new batch completion result.
*
* @param success indicates whether the completion is successful.
* @param failures set of any failures encountered
*/
public CompletedBatchOperation(boolean success, Set<? extends FlowRule> failures) {
this.success = success;
this.failures = ImmutableSet.copyOf(failures);
......@@ -40,5 +48,4 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> {
return failures;
}
}
......
/*
* 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.onlab.onos.net.intent;
/**
* Facade for receiving notifications from the intent batch service.
*/
public interface IntentBatchDelegate {
/**
* Submits the specified batch of intent operations for processing.
*
* @param operations batch of operations
*/
void execute(IntentOperations operations);
/**
* Cancesl the specified batch of intent operations.
*
* @param operations batch of operations to be cancelled
*/
void cancel(IntentOperations operations);
}
/*
* 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.onlab.onos.net.intent;
import java.util.Set;
/**
* Service for tracking and delegating batches of intent operations.
*/
public interface IntentBatchService {
/**
* Submits a batch of intent operations.
*
* @param operations batch of operations
*/
void addIntentOperations(IntentOperations operations);
/**
* Removes the specified batch of intent operations after completion.
*
* @param operations batch of operations
*/
void removeIntentOperations(IntentOperations operations);
/**
* Returns the set of intent batches currently being tracked.
* @return set of batches
*/
Set<IntentOperations> getIntentOperations();
/**
* Sets the batch service delegate.
*
* @param delegate delegate to apply
*/
void setDelegate(IntentBatchDelegate delegate);
/**
* Unsets the batch service delegate.
*
* @param delegate delegate to unset
*/
void unsetDelegate(IntentBatchDelegate delegate);
}
......@@ -15,7 +15,10 @@
*/
package org.onlab.onos.net.intent;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import java.util.List;
import java.util.Set;
/**
* Abstraction of a compiler which is capable of taking an intent
......@@ -27,9 +30,13 @@ public interface IntentCompiler<T extends Intent> {
/**
* Compiles the specified intent into other intents.
*
* @param intent intent to be compiled
* @param intent intent to be compiled
* @param installable previously compilation result; optional
* @param resources previously allocated resources; optional
* @return list of resulting intents
* @throws IntentException if issues are encountered while compiling the intent
*/
List<Intent> compile(T intent);
List<Intent> compile(T intent, List<Intent> installable,
Set<LinkResourceAllocations> resources);
}
......
......@@ -15,10 +15,10 @@
*/
package org.onlab.onos.net.intent;
import java.util.List;
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
import java.util.List;
/**
* Abstraction of entity capable of installing intents to the environment.
*/
......@@ -26,8 +26,8 @@ public interface IntentInstaller<T extends Intent> {
/**
* Installs the specified intent to the environment.
*
* @param intent intent to be installed
* @return FlowRule operations to install
* @param intent intent to be installed
* @return flow rule operations to complete install
* @throws IntentException if issues are encountered while installing the intent
*/
List<FlowRuleBatchOperation> install(T intent);
......@@ -35,9 +35,20 @@ public interface IntentInstaller<T extends Intent> {
/**
* Uninstalls the specified intent from the environment.
*
* @param intent intent to be uninstalled
* @return FlowRule operations to uninstall
* @param intent intent to be uninstalled
* @return flow rule operations to complete uninstall
* @throws IntentException if issues are encountered while uninstalling the intent
*/
List<FlowRuleBatchOperation> uninstall(T intent);
/**
* Replaces the specified intent with a new one in the environment.
*
* @param oldIntent intent to be removed
* @param newIntent intent to be installed
* @return flow rule operations to complete the replace
* @throws IntentException if issues are encountered while uninstalling the intent
*/
List<FlowRuleBatchOperation> replace(T oldIntent, T newIntent);
}
......
......@@ -15,6 +15,11 @@
*/
package org.onlab.onos.net.intent;
import java.util.Objects;
import static com.google.common.base.MoreObjects.toStringHelper;
/**
* Abstraction of an intent-related operation, e.g. add, remove, replace.
*/
......@@ -27,7 +32,7 @@ public class IntentOperation {
/**
* Operation type.
*/
enum Type {
public enum Type {
/**
* Indicates that an intent should be added.
*/
......@@ -41,15 +46,20 @@ public class IntentOperation {
/**
* Indicates that an intent should be replaced with another.
*/
REPLACE
REPLACE,
/**
* Indicates that an intent should be updated (i.e. recompiled/reinstalled).
*/
UPDATE,
}
/**
* Creates an intent operation.
*
* @param type operation type
* @param type operation type
* @param intentId identifier of the intent subject to the operation
* @param intent intent subject
* @param intent intent subject
*/
IntentOperation(Type type, IntentId intentId, Intent intent) {
this.type = type;
......@@ -85,4 +95,32 @@ public class IntentOperation {
return intent;
}
@Override
public int hashCode() {
return Objects.hash(type, intentId, intent);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final IntentOperation other = (IntentOperation) obj;
return Objects.equals(this.type, other.type) &&
Objects.equals(this.intentId, other.intentId) &&
Objects.equals(this.intent, other.intent);
}
@Override
public String toString() {
return toStringHelper(this)
.add("type", type)
.add("intentId", intentId)
.add("intent", intent)
.toString();
}
}
......
......@@ -18,11 +18,11 @@ package org.onlab.onos.net.intent;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.Objects;
import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onlab.onos.net.intent.IntentOperation.Type.REPLACE;
import static org.onlab.onos.net.intent.IntentOperation.Type.SUBMIT;
import static org.onlab.onos.net.intent.IntentOperation.Type.WITHDRAW;
import static org.onlab.onos.net.intent.IntentOperation.Type.*;
/**
* Batch of intent submit/withdraw/replace operations.
......@@ -58,6 +58,31 @@ public final class IntentOperations {
return new Builder();
}
@Override
public int hashCode() {
return Objects.hash(operations);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final IntentOperations other = (IntentOperations) obj;
return Objects.equals(this.operations, other.operations);
}
@Override
public String toString() {
return toStringHelper(this)
.add("operations", operations)
.toString();
}
/**
* Builder for batches of intent operations.
*/
......@@ -108,6 +133,18 @@ public final class IntentOperations {
}
/**
* Adds an intent update operation.
*
* @param intentId identifier of the intent to be updated
* @return self
*/
public Builder addUpdateOperation(IntentId intentId) {
checkNotNull(intentId, "Intent ID cannot be null");
builder.add(new IntentOperation(UPDATE, intentId, null));
return this;
}
/**
* Builds a batch of intent operations.
*
* @return immutable batch of intent operations
......
......@@ -17,7 +17,6 @@ package org.onlab.onos.net.intent;
import java.util.List;
import java.util.concurrent.Future;
/**
* Service for application submitting or withdrawing their intents.
......@@ -59,9 +58,8 @@ public interface IntentService {
* affected at later time.
* </p>
* @param operations batch of intent operations
* @return Future to get execution result
*/
Future<IntentOperations> execute(IntentOperations operations);
void execute(IntentOperations operations);
/**
* Returns an iterable of intents currently in the system.
......
......@@ -24,7 +24,6 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* Fake implementation of the intent service to assist in developing tests of
......@@ -104,7 +103,7 @@ public class FakeIntentManager implements TestableIntentService {
try {
// For the fake, we compile using a single level pass
List<Intent> installable = new ArrayList<>();
for (Intent compiled : getCompiler(intent).compile(intent)) {
for (Intent compiled : getCompiler(intent).compile(intent, null, null)) {
installable.add((Intent) compiled);
}
executeInstallingPhase(intent, installable);
......@@ -192,9 +191,8 @@ public class FakeIntentManager implements TestableIntentService {
}
@Override
public Future<IntentOperations> execute(IntentOperations operations) {
public void execute(IntentOperations operations) {
// TODO: implement later
return null;
}
@Override
......
......@@ -29,11 +29,13 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
import org.onlab.onos.net.resource.LinkResourceAllocations;
/**
* Suite of tests for the intent service contract.
......@@ -294,7 +296,8 @@ public class IntentServiceTest {
}
@Override
public List<Intent> compile(TestIntent intent) {
public List<Intent> compile(TestIntent intent, List<Intent> installable,
Set<LinkResourceAllocations> resources) {
if (fail) {
throw new IntentException("compile failed by design");
}
......@@ -326,6 +329,12 @@ public class IntentServiceTest {
}
return null;
}
@Override
public List<FlowRuleBatchOperation> replace(TestInstallableIntent intent,
TestInstallableIntent newIntent) {
return null;
}
}
}
......
......@@ -509,13 +509,8 @@ public class FlowRuleManager
boolean success = true;
Set<FlowRule> failed = Sets.newHashSet();
CompletedBatchOperation completed;
long start = System.nanoTime();
long end = start + unit.toNanos(timeout);
for (Future<CompletedBatchOperation> future : futures) {
long now = System.nanoTime();
long thisTimeout = end - now;
completed = future.get(thisTimeout, TimeUnit.NANOSECONDS);
completed = future.get(timeout, unit);
success = validateBatchOperation(failed, completed);
}
return finalizeBatchOperation(success, failed);
......
......@@ -27,9 +27,11 @@ import org.onlab.onos.net.host.HostService;
import org.onlab.onos.net.intent.HostToHostIntent;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.PathIntent;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import static org.onlab.onos.net.flow.DefaultTrafficSelector.builder;
......@@ -54,7 +56,8 @@ public class HostToHostIntentCompiler
}
@Override
public List<Intent> compile(HostToHostIntent intent) {
public List<Intent> compile(HostToHostIntent intent, List<Intent> installable,
Set<LinkResourceAllocations> resources) {
Path pathOne = getPath(intent, intent.one(), intent.two());
Path pathTwo = getPath(intent, intent.two(), intent.one());
......
......@@ -15,31 +15,10 @@
*/
package org.onlab.onos.net.intent.impl;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.onlab.onos.net.intent.IntentState.COMPILING;
import static org.onlab.onos.net.intent.IntentState.FAILED;
import static org.onlab.onos.net.intent.IntentState.INSTALLED;
import static org.onlab.onos.net.intent.IntentState.INSTALLING;
import static org.onlab.onos.net.intent.IntentState.RECOMPILING;
import static org.onlab.onos.net.intent.IntentState.WITHDRAWING;
import static org.onlab.onos.net.intent.IntentState.WITHDRAWN;
import static org.onlab.util.Tools.namedThreads;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -52,6 +31,8 @@ import org.onlab.onos.net.flow.CompletedBatchOperation;
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
import org.onlab.onos.net.flow.FlowRuleService;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentBatchDelegate;
import org.onlab.onos.net.intent.IntentBatchService;
import org.onlab.onos.net.intent.IntentCompiler;
import org.onlab.onos.net.intent.IntentEvent;
import org.onlab.onos.net.intent.IntentException;
......@@ -59,6 +40,7 @@ import org.onlab.onos.net.intent.IntentExtensionService;
import org.onlab.onos.net.intent.IntentId;
import org.onlab.onos.net.intent.IntentInstaller;
import org.onlab.onos.net.intent.IntentListener;
import org.onlab.onos.net.intent.IntentOperation;
import org.onlab.onos.net.intent.IntentOperations;
import org.onlab.onos.net.intent.IntentService;
import org.onlab.onos.net.intent.IntentState;
......@@ -66,9 +48,24 @@ import org.onlab.onos.net.intent.IntentStore;
import org.onlab.onos.net.intent.IntentStoreDelegate;
import org.slf4j.Logger;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.onlab.onos.net.intent.IntentState.*;
import static org.onlab.util.Tools.namedThreads;
import static org.slf4j.LoggerFactory.getLogger;
/**
* An implementation of Intent Manager.
......@@ -96,11 +93,15 @@ public class IntentManager
private final IntentStoreDelegate delegate = new InternalStoreDelegate();
private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentStore store;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentBatchService batchService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ObjectiveTrackerService trackerService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
......@@ -113,6 +114,7 @@ public class IntentManager
public void activate() {
store.setDelegate(delegate);
trackerService.setDelegate(topoDelegate);
batchService.setDelegate(batchDelegate);
eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
executor = newSingleThreadExecutor(namedThreads("onos-intents"));
monitorExecutor = newSingleThreadExecutor(namedThreads("onos-intent-monitor"));
......@@ -123,6 +125,7 @@ public class IntentManager
public void deactivate() {
store.unsetDelegate(delegate);
trackerService.unsetDelegate(topoDelegate);
batchService.unsetDelegate(batchDelegate);
eventDispatcher.removeSink(IntentEvent.class);
executor.shutdown();
monitorExecutor.shutdown();
......@@ -132,30 +135,27 @@ public class IntentManager
@Override
public void submit(Intent intent) {
checkNotNull(intent, INTENT_NULL);
registerSubclassCompilerIfNeeded(intent);
IntentEvent event = store.createIntent(intent);
if (event != null) {
eventDispatcher.post(event);
executor.execute(new IntentTask(COMPILING, intent));
}
execute(IntentOperations.builder().addSubmitOperation(intent).build());
}
@Override
public void withdraw(Intent intent) {
checkNotNull(intent, INTENT_NULL);
executor.execute(new IntentTask(WITHDRAWING, intent));
execute(IntentOperations.builder().addWithdrawOperation(intent.id()).build());
}
// FIXME: implement this method
@Override
public void replace(IntentId oldIntentId, Intent newIntent) {
throw new UnsupportedOperationException("execute() is not implemented yet");
checkNotNull(oldIntentId, INTENT_ID_NULL);
checkNotNull(newIntent, INTENT_NULL);
execute(IntentOperations.builder()
.addReplaceOperation(oldIntentId, newIntent)
.build());
}
// FIXME: implement this method
@Override
public Future<IntentOperations> execute(IntentOperations operations) {
throw new UnsupportedOperationException("execute() is not implemented yet");
public void execute(IntentOperations operations) {
batchService.addIntentOperations(operations);
}
@Override
......@@ -261,29 +261,25 @@ public class IntentManager
/**
* Compiles the specified intent.
*
* @param intent intent to be compiled
* @param update intent update
*/
private void executeCompilingPhase(Intent intent) {
private void executeCompilingPhase(IntentUpdate update) {
Intent intent = update.newIntent();
// Indicate that the intent is entering the compiling phase.
store.setState(intent, COMPILING);
update.setState(intent, COMPILING);
try {
// Compile the intent into installable derivatives.
List<Intent> installable = compileIntent(intent);
List<Intent> installables = compileIntent(intent, update);
// If all went well, associate the resulting list of installable
// intents with the top-level intent and proceed to install.
store.setInstallableIntents(intent.id(), installable);
executeInstallingPhase(intent);
} catch (Exception e) {
update.setInstallables(installables);
} catch (IntentException e) {
log.warn("Unable to compile intent {} due to:", intent.id(), e);
// If compilation failed, mark the intent as failed.
IntentEvent event = store.setState(intent, FAILED);
if (event != null) {
eventDispatcher.post(event);
}
update.setState(intent, FAILED);
}
}
......@@ -293,17 +289,18 @@ public class IntentManager
* @param intent intent
* @return result of compilation
*/
private List<Intent> compileIntent(Intent intent) {
private List<Intent> compileIntent(Intent intent, IntentUpdate update) {
if (intent.isInstallable()) {
return ImmutableList.of(intent);
}
registerSubclassCompilerIfNeeded(intent);
List<Intent> previous = update.oldInstallables();
// FIXME: get previous resources
List<Intent> installable = new ArrayList<>();
// TODO do we need to registerSubclassCompiler?
for (Intent compiled : getCompiler(intent).compile(intent)) {
installable.addAll(compileIntent(compiled));
for (Intent compiled : getCompiler(intent).compile(intent, previous, null)) {
installable.addAll(compileIntent(compiled, update));
}
return installable;
}
......@@ -311,63 +308,110 @@ public class IntentManager
* Installs all installable intents associated with the specified top-level
* intent.
*
* @param intent intent to be installed
* @param update intent update
*/
private void executeInstallingPhase(Intent intent) {
private void executeInstallingPhase(IntentUpdate update) {
if (update.newInstallables() == null) {
//no failed intents allowed past this point...
return;
}
// Indicate that the intent is entering the installing phase.
store.setState(intent, INSTALLING);
List<FlowRuleBatchOperation> installWork = Lists.newArrayList();
try {
List<Intent> installables = store.getInstallableIntents(intent.id());
if (installables != null) {
for (Intent installable : installables) {
registerSubclassInstallerIfNeeded(installable);
trackerService.addTrackedResources(intent.id(),
installable.resources());
List<FlowRuleBatchOperation> batch = getInstaller(installable).install(installable);
installWork.addAll(batch);
}
update.setState(update.newIntent(), INSTALLING);
List<FlowRuleBatchOperation> batches = Lists.newArrayList();
for (Intent installable : update.newInstallables()) {
registerSubclassInstallerIfNeeded(installable);
trackerService.addTrackedResources(update.newIntent().id(),
installable.resources());
try {
batches.addAll(getInstaller(installable).install(installable));
} catch (IntentException e) {
log.warn("Unable to install intent {} due to:", update.newIntent().id(), e);
//FIXME we failed... intent should be recompiled
// TODO: remove resources
// recompile!!!
}
// FIXME we have to wait for the installable intents
//eventDispatcher.post(store.setState(intent, INSTALLED));
monitorExecutor.execute(new IntentInstallMonitor(intent, installWork, INSTALLED));
} catch (Exception e) {
log.warn("Unable to install intent {} due to:", intent.id(), e);
uninstallIntent(intent, RECOMPILING);
}
update.setBatches(batches);
}
// If compilation failed, kick off the recompiling phase.
// FIXME
//executeRecompilingPhase(intent);
/**
* Uninstalls the specified intent by uninstalling all of its associated
* installable derivatives.
*
* @param update intent update
*/
private void executeWithdrawingPhase(IntentUpdate update) {
if (!update.oldIntent().equals(update.newIntent())) {
update.setState(update.oldIntent(), WITHDRAWING);
} // else newIntent is FAILED
uninstallIntent(update);
// If all went well, disassociate the top-level intent with its
// installable derivatives and mark it as withdrawn.
// FIXME need to clean up
//store.removeInstalledIntents(intent.id());
}
/**
* Uninstalls all installable intents associated with the given intent.
*
* @param update intent update
*/
//FIXME: need to handle next state properly
private void uninstallIntent(IntentUpdate update) {
if (update.oldInstallables == null) {
return;
}
List<FlowRuleBatchOperation> batches = Lists.newArrayList();
for (Intent installable : update.oldInstallables()) {
trackerService.removeTrackedResources(update.oldIntent().id(),
installable.resources());
try {
batches.addAll(getInstaller(installable).uninstall(installable));
} catch (IntentException e) {
log.warn("Unable to uninstall intent {} due to:", update.oldIntent().id(), e);
// TODO: this should never happen. but what if it does?
}
}
update.setBatches(batches);
// FIXME: next state for old is WITHDRAWN or FAILED
}
/**
* Recompiles the specified intent.
*
* @param intent intent to be recompiled
* @param update intent update
*/
private void executeRecompilingPhase(Intent intent) {
// FIXME: update this to work
private void executeRecompilingPhase(IntentUpdate update) {
Intent intent = update.newIntent();
// Indicate that the intent is entering the recompiling phase.
store.setState(intent, RECOMPILING);
List<FlowRuleBatchOperation> batches = Lists.newArrayList();
try {
// Compile the intent into installable derivatives.
List<Intent> installable = compileIntent(intent);
List<Intent> installable = compileIntent(intent, update);
// If all went well, compare the existing list of installable
// intents with the newly compiled list. If they are the same,
// bail, out since the previous approach was determined not to
// be viable.
// FIXME do we need this?
List<Intent> originalInstallable = store.getInstallableIntents(intent.id());
//FIXME let's be smarter about how we perform the update
//batches.addAll(uninstallIntent(intent, null));
if (Objects.equals(originalInstallable, installable)) {
eventDispatcher.post(store.setState(intent, FAILED));
} else {
// Otherwise, re-associate the newly compiled installable intents
// with the top-level intent and kick off installing phase.
store.setInstallableIntents(intent.id(), installable);
executeInstallingPhase(intent);
// FIXME commented out for now
//batches.addAll(executeInstallingPhase(update));
}
} catch (Exception e) {
log.warn("Unable to recompile intent {} due to:", intent.id(), e);
......@@ -378,45 +422,38 @@ public class IntentManager
}
/**
* Uninstalls the specified intent by uninstalling all of its associated
* installable derivatives.
*
* @param intent intent to be installed
*/
private void executeWithdrawingPhase(Intent intent) {
// Indicate that the intent is being withdrawn.
store.setState(intent, WITHDRAWING);
uninstallIntent(intent, WITHDRAWN);
// If all went well, disassociate the top-level intent with its
// installable derivatives and mark it as withdrawn.
// FIXME need to clean up
//store.removeInstalledIntents(intent.id());
// FIXME
//eventDispatcher.post(store.setState(intent, WITHDRAWN));
}
/**
* Uninstalls all installable intents associated with the given intent.
* Withdraws the old intent and installs the new intent as one operation.
*
* @param intent intent to be uninstalled
* @param update intent update
*/
private void uninstallIntent(Intent intent, IntentState nextState) {
List<FlowRuleBatchOperation> uninstallWork = Lists.newArrayList();
try {
List<Intent> installables = store.getInstallableIntents(intent.id());
if (installables != null) {
for (Intent installable : installables) {
trackerService.removeTrackedResources(intent.id(),
installable.resources());
List<FlowRuleBatchOperation> batches = getInstaller(installable).uninstall(installable);
uninstallWork.addAll(batches);
}
private void executeReplacementPhase(IntentUpdate update) {
checkArgument(update.oldInstallables().size() == update.newInstallables().size(),
"Old and New Intent must have equivalent installable intents.");
if (!update.oldIntent().equals(update.newIntent())) {
// only set the old intent's state if it is different
update.setState(update.oldIntent(), WITHDRAWING);
}
update.setState(update.newIntent(), INSTALLING);
List<FlowRuleBatchOperation> batches = Lists.newArrayList();
for (int i = 0; i < update.oldInstallables().size(); i++) {
Intent oldInstallable = update.oldInstallables().get(i);
Intent newInstallable = update.newInstallables().get(i);
if (oldInstallable.equals(newInstallable)) {
continue;
}
checkArgument(oldInstallable.getClass().equals(newInstallable.getClass()),
"Installable Intent type mismatch.");
trackerService.removeTrackedResources(update.oldIntent().id(), oldInstallable.resources());
trackerService.addTrackedResources(update.newIntent().id(), newInstallable.resources());
try {
batches.addAll(getInstaller(newInstallable).replace(oldInstallable, newInstallable));
} catch (IntentException e) {
log.warn("Unable to update intent {} due to:", update.oldIntent().id(), e);
//FIXME... we failed. need to uninstall (if same) or revert (if different)
}
monitorExecutor.execute(new IntentInstallMonitor(intent, uninstallWork, nextState));
} catch (IntentException e) {
log.warn("Unable to uninstall intent {} due to:", intent.id(), e);
}
update.setBatches(batches);
}
/**
......@@ -474,9 +511,6 @@ public class IntentManager
@Override
public void notify(IntentEvent event) {
eventDispatcher.post(event);
if (event.type() == IntentEvent.Type.SUBMITTED) {
executor.execute(new IntentTask(COMPILING, event.subject()));
}
}
}
......@@ -486,131 +520,349 @@ public class IntentManager
public void triggerCompile(Iterable<IntentId> intentIds,
boolean compileAllFailed) {
// Attempt recompilation of the specified intents first.
for (IntentId intentId : intentIds) {
Intent intent = getIntent(intentId);
uninstallIntent(intent, RECOMPILING);
//FIXME
//executeRecompilingPhase(intent);
IntentOperations.Builder builder = IntentOperations.builder();
for (IntentId id : intentIds) {
builder.addUpdateOperation(id);
}
if (compileAllFailed) {
// If required, compile all currently failed intents.
for (Intent intent : getIntents()) {
if (getIntentState(intent.id()) == FAILED) {
executeCompilingPhase(intent);
builder.addUpdateOperation(intent.id());
}
}
}
execute(builder.build());
}
}
/**
* TODO.
* @param op intent operation
* @return intent update
*/
private IntentUpdate processIntentOperation(IntentOperation op) {
IntentUpdate update = new IntentUpdate(op);
if (update.newIntent() != null) {
executeCompilingPhase(update);
}
if (update.oldInstallables() != null && update.newInstallables() != null) {
executeReplacementPhase(update);
} else if (update.newInstallables() != null) {
executeInstallingPhase(update);
} else if (update.oldInstallables() != null) {
executeWithdrawingPhase(update);
} else {
if (update.oldIntent() != null) {
// TODO this shouldn't happen
return update; //FIXME
}
if (update.newIntent() != null) {
// TODO assert that next state is failed
return update; //FIXME
}
}
return update;
}
// TODO comments...
private class IntentUpdate {
private final IntentOperation op;
private final Intent oldIntent;
private final Intent newIntent;
private final Map<Intent, IntentState> stateMap = Maps.newHashMap();
private final List<Intent> oldInstallables;
private List<Intent> newInstallables;
private List<FlowRuleBatchOperation> batches;
IntentUpdate(IntentOperation op) {
this.op = op;
switch (op.type()) {
case SUBMIT:
newIntent = op.intent();
oldIntent = null;
break;
case WITHDRAW:
newIntent = null;
oldIntent = store.getIntent(op.intentId());
break;
case REPLACE:
newIntent = op.intent();
oldIntent = store.getIntent(op.intentId());
break;
case UPDATE:
oldIntent = store.getIntent(op.intentId());
newIntent = oldIntent; //InnerAssignment: Inner assignments should be avoided.
break;
default:
oldIntent = null;
newIntent = null;
break;
}
// add new intent to store (if required)
if (newIntent != null) {
IntentEvent event = store.createIntent(newIntent);
if (event != null) {
eventDispatcher.post(event);
}
}
// fetch the old intent's installables from the store
if (oldIntent != null) {
oldInstallables = store.getInstallableIntents(oldIntent.id());
// TODO: remove intent from store after uninstall
} else {
oldInstallables = null;
}
}
Intent oldIntent() {
return oldIntent;
}
Intent newIntent() {
return newIntent;
}
List<Intent> oldInstallables() {
return oldInstallables;
}
List<Intent> newInstallables() {
return newInstallables;
}
void setInstallables(List<Intent> installables) {
newInstallables = installables;
store.setInstallableIntents(newIntent.id(), installables);
}
List<FlowRuleBatchOperation> batches() {
return batches;
}
void setBatches(List<FlowRuleBatchOperation> batches) {
this.batches = batches;
}
IntentState getState(Intent intent) {
return stateMap.get(intent);
}
void setState(Intent intent, IntentState newState) {
// TODO: clean this up, or set to debug
IntentState oldState = stateMap.get(intent);
log.info("intent id: {}, old state: {}, new state: {}",
intent.id(), oldState, newState);
stateMap.put(intent, newState);
IntentEvent event = store.setState(intent, newState);
if (event != null) {
eventDispatcher.post(event);
}
}
Map<Intent, IntentState> stateMap() {
return stateMap;
}
}
private static List<FlowRuleBatchOperation> mergeBatches(Map<IntentOperation,
IntentUpdate> intentUpdates) {
//TODO test this.
List<FlowRuleBatchOperation> batches = Lists.newArrayList();
for (IntentUpdate update : intentUpdates.values()) {
if (update.batches() == null) {
continue;
}
int i = 0;
for (FlowRuleBatchOperation batch : update.batches()) {
if (i == batches.size()) {
batches.add(batch);
} else {
FlowRuleBatchOperation existing = batches.get(i);
existing.addAll(batch);
}
i++;
}
}
return batches;
}
// Auxiliary runnable to perform asynchronous tasks.
private class IntentTask implements Runnable {
private final IntentState state;
private final Intent intent;
private final IntentOperations operations;
public IntentTask(IntentState state, Intent intent) {
this.state = state;
this.intent = intent;
public IntentTask(IntentOperations operations) {
this.operations = operations;
}
@Override
public void run() {
if (state == COMPILING) {
executeCompilingPhase(intent);
} else if (state == RECOMPILING) {
executeRecompilingPhase(intent);
} else if (state == WITHDRAWING) {
executeWithdrawingPhase(intent);
Map<IntentOperation, IntentUpdate> intentUpdates = Maps.newHashMap();
for (IntentOperation op : operations.operations()) {
intentUpdates.put(op, processIntentOperation(op));
}
List<FlowRuleBatchOperation> batches = mergeBatches(intentUpdates);
monitorExecutor.execute(new IntentInstallMonitor(operations, intentUpdates, batches));
}
}
private class IntentInstallMonitor implements Runnable {
private final Intent intent;
private static final long TIMEOUT = 5000; // ms
private final IntentOperations ops;
private final Map<IntentOperation, IntentUpdate> intentUpdateMap;
private final List<FlowRuleBatchOperation> work;
private final List<Future<CompletedBatchOperation>> futures;
private final IntentState nextState;
public IntentInstallMonitor(Intent intent,
List<FlowRuleBatchOperation> work,
IntentState nextState) {
this.intent = intent;
private Future<CompletedBatchOperation> future;
private final long startTime = System.currentTimeMillis();
private final long endTime = startTime + TIMEOUT;
public IntentInstallMonitor(IntentOperations ops,
Map<IntentOperation, IntentUpdate> intentUpdateMap,
List<FlowRuleBatchOperation> work) {
this.ops = ops;
this.intentUpdateMap = intentUpdateMap;
this.work = work;
// TODO how many Futures can be outstanding? one?
this.futures = Lists.newLinkedList();
this.nextState = nextState;
future = applyNextBatch();
}
// TODO need to kick off the first batch sometime, why not now?
futures.add(applyNextBatch());
/**
* Applies the next batch, and returns the future.
*
* @return Future for next batch
*/
private Future<CompletedBatchOperation> applyNextBatch() {
if (work.isEmpty()) {
return null;
}
FlowRuleBatchOperation batch = work.remove(0);
return flowRuleService.applyBatch(batch);
}
/**
* Update the intent store with the next status for this intent.
*/
private void updateIntent() {
private void updateIntents() {
// FIXME we assume everything passes for now.
for (IntentUpdate update : intentUpdateMap.values()) {
for (Intent intent : update.stateMap().keySet()) {
switch (update.getState(intent)) {
case INSTALLING:
update.setState(intent, INSTALLED);
break;
case WITHDRAWING:
update.setState(intent, WITHDRAWN);
// Fall-through
case FAILED:
store.removeInstalledIntents(intent.id());
break;
case SUBMITTED:
case COMPILING:
case RECOMPILING:
case WITHDRAWN:
case INSTALLED:
default:
//FIXME clean this up (we shouldn't ever get here)
log.warn("Bad state: {} for {}", update.getState(intent), intent);
break;
}
}
}
/*
for (IntentOperation op : ops.operations()) {
switch (op.type()) {
case SUBMIT:
store.setState(op.intent(), INSTALLED);
break;
case WITHDRAW:
Intent intent = store.getIntent(op.intentId());
store.setState(intent, WITHDRAWN);
break;
case REPLACE:
store.setState(op.intent(), INSTALLED);
intent = store.getIntent(op.intentId());
store.setState(intent, WITHDRAWN);
break;
case UPDATE:
intent = store.getIntent(op.intentId());
store.setState(intent, INSTALLED);
break;
default:
break;
}
}
*/
/*
if (nextState == RECOMPILING) {
executor.execute(new IntentTask(nextState, intent));
eventDispatcher.post(store.setState(intent, FAILED));
// FIXME try to recompile
// executor.execute(new IntentTask(nextState, intent));
} else if (nextState == INSTALLED || nextState == WITHDRAWN) {
eventDispatcher.post(store.setState(intent, nextState));
} else {
log.warn("Invalid next intent state {} for intent {}", nextState, intent);
}
}
/**
* Applies the next batch.
*/
private Future<CompletedBatchOperation> applyNextBatch() {
if (work.isEmpty()) {
return null;
}
FlowRuleBatchOperation batch = work.remove(0);
return flowRuleService.applyBatch(batch);
}*/
}
/**
* Iterate through the pending futures, and remove them when they have completed.
*/
private void processFutures() {
List<Future<CompletedBatchOperation>> newFutures = Lists.newArrayList();
for (Iterator<Future<CompletedBatchOperation>> i = futures.iterator(); i.hasNext();) {
Future<CompletedBatchOperation> future = i.next();
try {
// TODO: we may want to get the future here and go back to the future.
CompletedBatchOperation completed = future.get(100, TimeUnit.NANOSECONDS);
if (completed.isSuccess()) {
Future<CompletedBatchOperation> newFuture = applyNextBatch();
if (newFuture != null) {
// we'll add this later so that we don't get a ConcurrentModException
newFutures.add(newFuture);
}
} else {
// TODO check if future succeeded and if not report fail items
log.warn("Failed items: {}", completed.failedItems());
// TODO revert....
//uninstallIntent(intent, RECOMPILING);
}
i.remove();
} catch (TimeoutException | InterruptedException | ExecutionException te) {
log.debug("Intallations of intent {} is still pending", intent);
if (future == null) {
return; //FIXME look at this
}
try {
CompletedBatchOperation completed = future.get(100, TimeUnit.NANOSECONDS);
if (completed.isSuccess()) {
future = applyNextBatch();
} else {
// TODO check if future succeeded and if not report fail items
log.warn("Failed items: {}", completed.failedItems());
// FIXME revert.... by submitting a new batch
//uninstallIntent(intent, RECOMPILING);
}
} catch (TimeoutException | InterruptedException | ExecutionException te) {
//TODO look into error message
log.debug("Intallations of intent {} is still pending", ops);
}
futures.addAll(newFutures);
}
@Override
public void run() {
processFutures();
if (futures.isEmpty()) {
if (future == null) {
// woohoo! we are done!
updateIntent();
updateIntents();
batchService.removeIntentOperations(ops);
} else if (endTime < System.currentTimeMillis()) {
log.warn("Install request timed out");
// future.cancel(true);
// TODO retry and/or report the failure
} else {
// resubmit ourselves if we are not done yet
monitorExecutor.submit(this);
}
}
}
private class InternalBatchDelegate implements IntentBatchDelegate {
@Override
public void execute(IntentOperations operations) {
log.info("Execute operations: {}", operations);
//FIXME: perhaps we want to track this task so that we can cancel it.
executor.execute(new IntentTask(operations));
}
@Override
public void cancel(IntentOperations operations) {
//FIXME: implement this
log.warn("NOT IMPLEMENTED -- Cancel operations: {}", operations);
}
}
}
......
......@@ -111,6 +111,13 @@ public class LinkCollectionIntentInstaller implements IntentInstaller<LinkCollec
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
}
@Override
public List<FlowRuleBatchOperation> replace(LinkCollectionIntent intent,
LinkCollectionIntent newIntent) {
// FIXME: implement
return null;
}
/**
* Creates a FlowRuleBatchEntry based on the provided parameters.
*
......
......@@ -29,6 +29,7 @@ import org.onlab.onos.net.intent.IntentExtensionService;
import org.onlab.onos.net.intent.LinkCollectionIntent;
import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
import org.onlab.onos.net.intent.PointToPointIntent;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import org.onlab.onos.net.topology.PathService;
import java.util.Arrays;
......@@ -61,7 +62,8 @@ public class MultiPointToSinglePointIntentCompiler
}
@Override
public List<Intent> compile(MultiPointToSinglePointIntent intent) {
public List<Intent> compile(MultiPointToSinglePointIntent intent, List<Intent> installable,
Set<LinkResourceAllocations> resources) {
Set<Link> links = new HashSet<>();
for (ConnectPoint ingressPoint : intent.ingressPoints()) {
......
......@@ -29,6 +29,7 @@ import org.onlab.onos.net.intent.IntentCompiler;
import org.onlab.onos.net.intent.IntentExtensionService;
import org.onlab.onos.net.intent.OpticalConnectivityIntent;
import org.onlab.onos.net.intent.OpticalPathIntent;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import org.onlab.onos.net.topology.LinkWeight;
import org.onlab.onos.net.topology.Topology;
import org.onlab.onos.net.topology.TopologyEdge;
......@@ -60,7 +61,9 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
}
@Override
public List<Intent> compile(OpticalConnectivityIntent intent) {
public List<Intent> compile(OpticalConnectivityIntent intent,
List<Intent> installable,
Set<LinkResourceAllocations> resources) {
// TODO: compute multiple paths using the K-shortest path algorithm
Path path = calculateOpticalPath(intent.getSrcConnectPoint(), intent.getDst());
Intent newIntent = new OpticalPathIntent(intent.appId(),
......
......@@ -104,6 +104,13 @@ public class OpticalPathIntentInstaller implements IntentInstaller<OpticalPathIn
return generateRules(intent, allocations, FlowRuleOperation.REMOVE);
}
@Override
public List<FlowRuleBatchOperation> replace(OpticalPathIntent intent,
OpticalPathIntent newIntent) {
// FIXME: implement this
return null;
}
private LinkResourceAllocations assignWavelength(OpticalPathIntent intent) {
LinkResourceRequest.Builder request = DefaultLinkResourceRequest.builder(intent.id(),
intent.path().links())
......
......@@ -131,6 +131,15 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
}
@Override
public List<FlowRuleBatchOperation> replace(PathIntent oldIntent, PathIntent newIntent) {
// FIXME: implement this
List<FlowRuleBatchOperation> batches = Lists.newArrayList();
batches.addAll(uninstall(oldIntent));
batches.addAll(install(newIntent));
return batches;
}
/**
* Allocate resources required for an intent.
*
......@@ -147,7 +156,7 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
return request.resources().isEmpty() ? null : resourceService.requestResources(request);
}
// TODO refactor below this line... ----------------------------
// FIXME refactor below this line... ----------------------------
/**
* Generates the series of MatchActionOperations from the
......
......@@ -28,9 +28,11 @@ import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.PathIntent;
import org.onlab.onos.net.intent.PointToPointIntent;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static java.util.Arrays.asList;
import static org.onlab.onos.net.Link.Type.DIRECT;
......@@ -57,7 +59,9 @@ public class PointToPointIntentCompiler
}
@Override
public List<Intent> compile(PointToPointIntent intent) {
public List<Intent> compile(PointToPointIntent intent, List<Intent> installable,
Set<LinkResourceAllocations> resources) {
ConnectPoint ingressPoint = intent.ingressPoint();
ConnectPoint egressPoint = intent.egressPoint();
......
......@@ -87,7 +87,7 @@ public class PathConstraintCalculationTest {
constraints);
final PointToPointIntentCompiler compiler = makeCompiler(resourceService);
return compiler.compile(intent);
return compiler.compile(intent, null, null);
}
/**
......
......@@ -121,7 +121,7 @@ public class TestHostToHostIntentCompiler {
HostToHostIntentCompiler compiler = makeCompiler(hops);
assertThat(compiler, is(notNullValue()));
List<Intent> result = compiler.compile(intent);
List<Intent> result = compiler.compile(intent, null, null);
assertThat(result, is(Matchers.notNullValue()));
assertThat(result, hasSize(2));
Intent forwardResultIntent = result.get(0);
......
......@@ -137,7 +137,7 @@ public class TestMultiPointToSinglePointIntentCompiler {
MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
assertThat(compiler, is(notNullValue()));
List<Intent> result = compiler.compile(intent);
List<Intent> result = compiler.compile(intent, null, null);
assertThat(result, is(Matchers.notNullValue()));
assertThat(result, hasSize(1));
Intent resultIntent = result.get(0);
......@@ -172,7 +172,7 @@ public class TestMultiPointToSinglePointIntentCompiler {
MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
assertThat(compiler, is(notNullValue()));
List<Intent> result = compiler.compile(intent);
List<Intent> result = compiler.compile(intent, null, null);
assertThat(result, is(notNullValue()));
assertThat(result, hasSize(1));
Intent resultIntent = result.get(0);
......@@ -205,7 +205,7 @@ public class TestMultiPointToSinglePointIntentCompiler {
MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
assertThat(compiler, is(notNullValue()));
List<Intent> result = compiler.compile(intent);
List<Intent> result = compiler.compile(intent, null, null);
assertThat(result, is(notNullValue()));
assertThat(result, hasSize(1));
Intent resultIntent = result.get(0);
......
......@@ -93,7 +93,7 @@ public class TestPointToPointIntentCompiler {
PointToPointIntentCompiler compiler = makeCompiler(hops);
assertThat(compiler, is(notNullValue()));
List<Intent> result = compiler.compile(intent);
List<Intent> result = compiler.compile(intent, null, null);
assertThat(result, is(Matchers.notNullValue()));
assertThat(result, hasSize(1));
Intent forwardResultIntent = result.get(0);
......@@ -126,7 +126,7 @@ public class TestPointToPointIntentCompiler {
PointToPointIntentCompiler compiler = makeCompiler(hops);
assertThat(compiler, is(notNullValue()));
List<Intent> result = compiler.compile(intent);
List<Intent> result = compiler.compile(intent, null, null);
assertThat(result, is(Matchers.notNullValue()));
assertThat(result, hasSize(1));
Intent reverseResultIntent = result.get(0);
......@@ -157,7 +157,7 @@ public class TestPointToPointIntentCompiler {
String[] hops = {"1"};
PointToPointIntentCompiler sut = makeCompiler(hops);
List<Intent> compiled = sut.compile(intent);
List<Intent> compiled = sut.compile(intent, null, null);
assertThat(compiled, hasSize(1));
assertThat(compiled.get(0), is(instanceOf(PathIntent.class)));
......
/*
* 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.onlab.onos.store.trivial.impl;
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;
import org.apache.felix.scr.annotations.Service;
import org.onlab.onos.net.intent.IntentBatchDelegate;
import org.onlab.onos.net.intent.IntentBatchService;
import org.onlab.onos.net.intent.IntentOperations;
import org.slf4j.Logger;
import java.util.HashSet;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.slf4j.LoggerFactory.getLogger;
@Component(immediate = true)
@Service
public class SimpleIntentBatchQueue implements IntentBatchService {
private final Logger log = getLogger(getClass());
private final Set<IntentOperations> pendingBatches = new HashSet<>();
private IntentBatchDelegate delegate;
@Activate
public void activate() {
log.info("Started");
}
@Deactivate
public void deactivate() {
log.info("Stopped");
}
@Override
public void addIntentOperations(IntentOperations operations) {
checkState(delegate != null, "No delegate set");
pendingBatches.add(operations);
delegate.execute(operations);
}
@Override
public void removeIntentOperations(IntentOperations operations) {
pendingBatches.remove(operations);
}
@Override
public Set<IntentOperations> getIntentOperations() {
return ImmutableSet.copyOf(pendingBatches);
}
@Override
public void setDelegate(IntentBatchDelegate delegate) {
this.delegate = checkNotNull(delegate, "Delegate cannot be null");
}
@Override
public void unsetDelegate(IntentBatchDelegate delegate) {
if (this.delegate != null && this.delegate.equals(delegate)) {
this.delegate = null;
}
}
}
......@@ -33,7 +33,7 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static org.onlab.onos.net.intent.IntentState.*;
import static org.onlab.onos.net.intent.IntentState.WITHDRAWN;
import static org.slf4j.LoggerFactory.getLogger;
@Component(immediate = true)
......@@ -45,8 +45,8 @@ public class SimpleIntentStore
private final Logger log = getLogger(getClass());
private final Map<IntentId, Intent> intents = new ConcurrentHashMap<>();
private final Map<IntentId, IntentState> states = new ConcurrentHashMap<>();
private final Map<IntentId, List<Intent>> installable =
new ConcurrentHashMap<>();
private final Map<IntentId, List<Intent>> installable = new ConcurrentHashMap<>();
@Activate
public void activate() {
......@@ -60,6 +60,9 @@ public class SimpleIntentStore
@Override
public IntentEvent createIntent(Intent intent) {
if (intents.containsKey(intent.id())) {
return null;
}
intents.put(intent.id(), intent);
return this.setState(intent, IntentState.SUBMITTED);
}
......