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
This commit is contained in:
Brian O'Connor 2014-10-30 13:20:05 -07:00 committed by Gerrit Code Review
parent a88d1f5943
commit fa81eaef06
27 changed files with 829 additions and 252 deletions

View File

@ -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);

View File

@ -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) {

View File

@ -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;
}
}

View File

@ -0,0 +1,36 @@
/*
* 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);
}

View File

@ -0,0 +1,59 @@
/*
* 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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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.
*/
@ -107,6 +132,18 @@ public final class IntentOperations {
return this;
}
/**
* 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.
*

View File

@ -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.

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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());

View File

@ -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,10 +93,14 @@ 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;
@ -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) {
// 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);
}
}
// 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);
// If compilation failed, kick off the recompiling phase.
// FIXME
//executeRecompilingPhase(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.
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!!!
}
}
update.setBatches(batches);
}
/**
* 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.
* Withdraws the old intent and installs the new intent as one operation.
*
* @param intent intent to be installed
* @param update intent update
*/
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.
*
* @param intent intent to be uninstalled
*/
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);
}
}
monitorExecutor.execute(new IntentInstallMonitor(intent, uninstallWork, nextState));
} catch (IntentException e) {
log.warn("Unable to uninstall intent {} due to:", intent.id(), e);
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)
}
}
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,82 +520,221 @@ 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;
private Future<CompletedBatchOperation> future;
private final long startTime = System.currentTimeMillis();
private final long endTime = startTime + TIMEOUT;
public IntentInstallMonitor(Intent intent,
List<FlowRuleBatchOperation> work,
IntentState nextState) {
this.intent = intent;
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;
// TODO need to kick off the first batch sometime, why not now?
futures.add(applyNextBatch());
future = applyNextBatch();
}
/**
* Update the intent store with the next status for this intent.
*/
private void updateIntent() {
if (nextState == RECOMPILING) {
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.
* Applies the next batch, and returns the future.
*
* @return Future for next batch
*/
private Future<CompletedBatchOperation> applyNextBatch() {
if (work.isEmpty()) {
@ -571,46 +744,125 @@ public class IntentManager
return flowRuleService.applyBatch(batch);
}
/**
* Update the intent store with the next status for this intent.
*/
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) {
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);
}*/
}
/**
* 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);
}
}
}

View File

@ -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.
*

View File

@ -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()) {

View File

@ -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(),

View File

@ -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())

View File

@ -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

View File

@ -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();

View File

@ -87,7 +87,7 @@ public class PathConstraintCalculationTest {
constraints);
final PointToPointIntentCompiler compiler = makeCompiler(resourceService);
return compiler.compile(intent);
return compiler.compile(intent, null, null);
}
/**

View File

@ -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);

View File

@ -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);

View File

@ -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)));

View File

@ -0,0 +1,81 @@
/*
* 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;
}
}
}

View File

@ -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);
}