diff --git a/cli/src/main/java/org/onlab/onos/cli/net/IntentPushTestCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/IntentPushTestCommand.java index 202326b383..2cb402aacc 100644 --- a/cli/src/main/java/org/onlab/onos/cli/net/IntentPushTestCommand.java +++ b/cli/src/main/java/org/onlab/onos/cli/net/IntentPushTestCommand.java @@ -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); diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/BatchOperation.java b/core/api/src/main/java/org/onlab/onos/net/flow/BatchOperation.java index 16ce1844a0..6fd16b90e8 100644 --- a/core/api/src/main/java/org/onlab/onos/net/flow/BatchOperation.java +++ b/core/api/src/main/java/org/onlab/onos/net/flow/BatchOperation.java @@ -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> { 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 another) { + return ops.addAll(another.getOperations()); + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/CompletedBatchOperation.java b/core/api/src/main/java/org/onlab/onos/net/flow/CompletedBatchOperation.java index 3758ea964d..b9887441a2 100644 --- a/core/api/src/main/java/org/onlab/onos/net/flow/CompletedBatchOperation.java +++ b/core/api/src/main/java/org/onlab/onos/net/flow/CompletedBatchOperation.java @@ -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 { - private final boolean success; private final Set 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 failures) { this.success = success; this.failures = ImmutableSet.copyOf(failures); @@ -40,5 +48,4 @@ public class CompletedBatchOperation implements BatchOperationResult { return failures; } - } diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentBatchDelegate.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentBatchDelegate.java new file mode 100644 index 0000000000..248d82e872 --- /dev/null +++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentBatchDelegate.java @@ -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); +} diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentBatchService.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentBatchService.java new file mode 100644 index 0000000000..37a1d4adf5 --- /dev/null +++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentBatchService.java @@ -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 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); + +} diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentCompiler.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentCompiler.java index f6dcd17af2..2d6d94b759 100644 --- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentCompiler.java +++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentCompiler.java @@ -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 { /** * 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 compile(T intent); + List compile(T intent, List installable, + Set resources); + } diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentInstaller.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentInstaller.java index 93d8a40078..5ef717fafe 100644 --- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentInstaller.java +++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentInstaller.java @@ -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 { /** * 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 install(T intent); @@ -35,9 +35,20 @@ public interface IntentInstaller { /** * 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 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 replace(T oldIntent, T newIntent); + } diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperation.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperation.java index 902f41894b..28508b6af5 100644 --- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperation.java +++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperation.java @@ -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(); + } } diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperations.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperations.java index 9e31ca345c..eca51f0821 100644 --- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperations.java +++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperations.java @@ -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. * diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentService.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentService.java index 090af63c67..9abb58454b 100644 --- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentService.java +++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentService.java @@ -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. *

* @param operations batch of intent operations - * @return Future to get execution result */ - Future execute(IntentOperations operations); + void execute(IntentOperations operations); /** * Returns an iterable of intents currently in the system. diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/FakeIntentManager.java b/core/api/src/test/java/org/onlab/onos/net/intent/FakeIntentManager.java index 9f4755ae81..d6732c71c9 100644 --- a/core/api/src/test/java/org/onlab/onos/net/intent/FakeIntentManager.java +++ b/core/api/src/test/java/org/onlab/onos/net/intent/FakeIntentManager.java @@ -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 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 execute(IntentOperations operations) { + public void execute(IntentOperations operations) { // TODO: implement later - return null; } @Override diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/IntentServiceTest.java b/core/api/src/test/java/org/onlab/onos/net/intent/IntentServiceTest.java index 86ebc5936d..a7004a275c 100644 --- a/core/api/src/test/java/org/onlab/onos/net/intent/IntentServiceTest.java +++ b/core/api/src/test/java/org/onlab/onos/net/intent/IntentServiceTest.java @@ -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 compile(TestIntent intent) { + public List compile(TestIntent intent, List installable, + Set resources) { if (fail) { throw new IntentException("compile failed by design"); } @@ -326,6 +329,12 @@ public class IntentServiceTest { } return null; } + + @Override + public List replace(TestInstallableIntent intent, + TestInstallableIntent newIntent) { + return null; + } } } diff --git a/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java b/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java index c1ba8af55f..d356d9a5a4 100644 --- a/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java +++ b/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java @@ -509,13 +509,8 @@ public class FlowRuleManager boolean success = true; Set failed = Sets.newHashSet(); CompletedBatchOperation completed; - long start = System.nanoTime(); - long end = start + unit.toNanos(timeout); - for (Future 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); diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java index 4d989ac251..fdab18ed48 100644 --- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java +++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java @@ -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 compile(HostToHostIntent intent) { + public List compile(HostToHostIntent intent, List installable, + Set resources) { Path pathOne = getPath(intent, intent.one(), intent.two()); Path pathTwo = getPath(intent, intent.two(), intent.one()); diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java index af2af248d5..e64fe82b26 100644 --- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java +++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java @@ -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 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 installable = compileIntent(intent); + List 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 compileIntent(Intent intent) { + private List compileIntent(Intent intent, IntentUpdate update) { if (intent.isInstallable()) { return ImmutableList.of(intent); } + registerSubclassCompilerIfNeeded(intent); + List previous = update.oldInstallables(); + // FIXME: get previous resources List 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 installWork = Lists.newArrayList(); - try { - List installables = store.getInstallableIntents(intent.id()); - if (installables != null) { - for (Intent installable : installables) { - registerSubclassInstallerIfNeeded(installable); - trackerService.addTrackedResources(intent.id(), - installable.resources()); - List 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 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 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 batches = Lists.newArrayList(); try { // Compile the intent into installable derivatives. - List installable = compileIntent(intent); + List 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 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 uninstallWork = Lists.newArrayList(); - try { - List installables = store.getInstallableIntents(intent.id()); - if (installables != null) { - for (Intent installable : installables) { - trackerService.removeTrackedResources(intent.id(), - installable.resources()); - List 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 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 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 stateMap = Maps.newHashMap(); + + private final List oldInstallables; + private List newInstallables; + private List 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 oldInstallables() { + return oldInstallables; + } + + List newInstallables() { + return newInstallables; + } + + void setInstallables(List installables) { + newInstallables = installables; + store.setInstallableIntents(newIntent.id(), installables); + } + + List batches() { + return batches; + } + + void setBatches(List 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 stateMap() { + return stateMap; + } + } + + private static List mergeBatches(Map intentUpdates) { + //TODO test this. + List 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 intentUpdates = Maps.newHashMap(); + for (IntentOperation op : operations.operations()) { + intentUpdates.put(op, processIntentOperation(op)); } + List 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 intentUpdateMap; private final List work; - private final List> futures; - private final IntentState nextState; + private Future future; + private final long startTime = System.currentTimeMillis(); + private final long endTime = startTime + TIMEOUT; - public IntentInstallMonitor(Intent intent, - List work, - IntentState nextState) { - this.intent = intent; + public IntentInstallMonitor(IntentOperations ops, + Map intentUpdateMap, + List 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 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> newFutures = Lists.newArrayList(); - for (Iterator> i = futures.iterator(); i.hasNext();) { - Future 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 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); + } + } } diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/LinkCollectionIntentInstaller.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/LinkCollectionIntentInstaller.java index 4a689a15b1..0524d76f81 100644 --- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/LinkCollectionIntentInstaller.java +++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/LinkCollectionIntentInstaller.java @@ -111,6 +111,13 @@ public class LinkCollectionIntentInstaller implements IntentInstaller replace(LinkCollectionIntent intent, + LinkCollectionIntent newIntent) { + // FIXME: implement + return null; + } + /** * Creates a FlowRuleBatchEntry based on the provided parameters. * diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/MultiPointToSinglePointIntentCompiler.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/MultiPointToSinglePointIntentCompiler.java index b01500a784..9b8b149df1 100644 --- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/MultiPointToSinglePointIntentCompiler.java +++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/MultiPointToSinglePointIntentCompiler.java @@ -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 compile(MultiPointToSinglePointIntent intent) { + public List compile(MultiPointToSinglePointIntent intent, List installable, + Set resources) { Set links = new HashSet<>(); for (ConnectPoint ingressPoint : intent.ingressPoints()) { diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/OpticalConnectivityIntentCompiler.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/OpticalConnectivityIntentCompiler.java index 3683e8e4f5..066d730216 100644 --- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/OpticalConnectivityIntentCompiler.java +++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/OpticalConnectivityIntentCompiler.java @@ -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 compile(OpticalConnectivityIntent intent) { + public List compile(OpticalConnectivityIntent intent, + List installable, + Set resources) { // TODO: compute multiple paths using the K-shortest path algorithm Path path = calculateOpticalPath(intent.getSrcConnectPoint(), intent.getDst()); Intent newIntent = new OpticalPathIntent(intent.appId(), diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/OpticalPathIntentInstaller.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/OpticalPathIntentInstaller.java index 27b53875c2..c102a6ee97 100644 --- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/OpticalPathIntentInstaller.java +++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/OpticalPathIntentInstaller.java @@ -104,6 +104,13 @@ public class OpticalPathIntentInstaller implements IntentInstaller 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()) diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathIntentInstaller.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathIntentInstaller.java index 2505be5dd9..0e8abca4f9 100644 --- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathIntentInstaller.java +++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathIntentInstaller.java @@ -131,6 +131,15 @@ public class PathIntentInstaller implements IntentInstaller { return Lists.newArrayList(new FlowRuleBatchOperation(rules)); } + @Override + public List replace(PathIntent oldIntent, PathIntent newIntent) { + // FIXME: implement this + List 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 { 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 diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/PointToPointIntentCompiler.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PointToPointIntentCompiler.java index efdc4bdf49..a4c8d582f9 100644 --- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/PointToPointIntentCompiler.java +++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PointToPointIntentCompiler.java @@ -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 compile(PointToPointIntent intent) { + public List compile(PointToPointIntent intent, List installable, + Set resources) { + ConnectPoint ingressPoint = intent.ingressPoint(); ConnectPoint egressPoint = intent.egressPoint(); diff --git a/core/net/src/test/java/org/onlab/onos/net/intent/impl/PathConstraintCalculationTest.java b/core/net/src/test/java/org/onlab/onos/net/intent/impl/PathConstraintCalculationTest.java index 3e8e7c1794..548ea37a2a 100644 --- a/core/net/src/test/java/org/onlab/onos/net/intent/impl/PathConstraintCalculationTest.java +++ b/core/net/src/test/java/org/onlab/onos/net/intent/impl/PathConstraintCalculationTest.java @@ -87,7 +87,7 @@ public class PathConstraintCalculationTest { constraints); final PointToPointIntentCompiler compiler = makeCompiler(resourceService); - return compiler.compile(intent); + return compiler.compile(intent, null, null); } /** diff --git a/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestHostToHostIntentCompiler.java b/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestHostToHostIntentCompiler.java index 02fa4db79f..a0903fde7c 100644 --- a/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestHostToHostIntentCompiler.java +++ b/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestHostToHostIntentCompiler.java @@ -121,7 +121,7 @@ public class TestHostToHostIntentCompiler { HostToHostIntentCompiler compiler = makeCompiler(hops); assertThat(compiler, is(notNullValue())); - List result = compiler.compile(intent); + List result = compiler.compile(intent, null, null); assertThat(result, is(Matchers.notNullValue())); assertThat(result, hasSize(2)); Intent forwardResultIntent = result.get(0); diff --git a/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestMultiPointToSinglePointIntentCompiler.java b/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestMultiPointToSinglePointIntentCompiler.java index e85d090256..4e49fab628 100644 --- a/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestMultiPointToSinglePointIntentCompiler.java +++ b/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestMultiPointToSinglePointIntentCompiler.java @@ -137,7 +137,7 @@ public class TestMultiPointToSinglePointIntentCompiler { MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops); assertThat(compiler, is(notNullValue())); - List result = compiler.compile(intent); + List 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 result = compiler.compile(intent); + List 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 result = compiler.compile(intent); + List result = compiler.compile(intent, null, null); assertThat(result, is(notNullValue())); assertThat(result, hasSize(1)); Intent resultIntent = result.get(0); diff --git a/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestPointToPointIntentCompiler.java b/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestPointToPointIntentCompiler.java index 7f7e6d38ee..6521f24d28 100644 --- a/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestPointToPointIntentCompiler.java +++ b/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestPointToPointIntentCompiler.java @@ -93,7 +93,7 @@ public class TestPointToPointIntentCompiler { PointToPointIntentCompiler compiler = makeCompiler(hops); assertThat(compiler, is(notNullValue())); - List result = compiler.compile(intent); + List 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 result = compiler.compile(intent); + List 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 compiled = sut.compile(intent); + List compiled = sut.compile(intent, null, null); assertThat(compiled, hasSize(1)); assertThat(compiled.get(0), is(instanceOf(PathIntent.class))); diff --git a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleIntentBatchQueue.java b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleIntentBatchQueue.java new file mode 100644 index 0000000000..b8d22bfb74 --- /dev/null +++ b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleIntentBatchQueue.java @@ -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 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 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; + } + } +} diff --git a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleIntentStore.java b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleIntentStore.java index c28adf5fff..5a91276f48 100644 --- a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleIntentStore.java +++ b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleIntentStore.java @@ -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 intents = new ConcurrentHashMap<>(); private final Map states = new ConcurrentHashMap<>(); - private final Map> installable = - new ConcurrentHashMap<>(); + private final Map> 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); }