mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-10-17 18:32:28 +02:00
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:
parent
a88d1f5943
commit
fa81eaef06
@ -29,6 +29,7 @@ import org.onlab.onos.net.intent.Intent;
|
||||
import org.onlab.onos.net.intent.IntentEvent;
|
||||
import org.onlab.onos.net.intent.IntentEvent.Type;
|
||||
import org.onlab.onos.net.intent.IntentListener;
|
||||
import org.onlab.onos.net.intent.IntentOperations;
|
||||
import org.onlab.onos.net.intent.IntentService;
|
||||
import org.onlab.onos.net.intent.PointToPointIntent;
|
||||
import org.onlab.packet.Ethernet;
|
||||
@ -63,9 +64,6 @@ public class IntentPushTestCommand extends AbstractShellCommand
|
||||
required = true, multiValued = false)
|
||||
String countString = null;
|
||||
|
||||
|
||||
private static long id = 0x7870001;
|
||||
|
||||
private IntentService service;
|
||||
private CountDownLatch latch;
|
||||
private long start, end;
|
||||
@ -91,15 +89,18 @@ public class IntentPushTestCommand extends AbstractShellCommand
|
||||
service.addListener(this);
|
||||
latch = new CountDownLatch(count);
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < count; i++) {
|
||||
IntentOperations.Builder ops = IntentOperations.builder();
|
||||
for (int i = 1; i <= count; i++) {
|
||||
TrafficSelector s = selector
|
||||
.matchEthSrc(MacAddress.valueOf(i))
|
||||
.build();
|
||||
Intent intent = new PointToPointIntent(appId(), s, treatment,
|
||||
ingress, egress);
|
||||
service.submit(intent);
|
||||
ops.addSubmitOperation(intent);
|
||||
}
|
||||
IntentOperations operations = ops.build();
|
||||
start = System.currentTimeMillis();
|
||||
service.execute(operations);
|
||||
try {
|
||||
if (latch.await(10, TimeUnit.SECONDS)) {
|
||||
printResults(count);
|
||||
|
@ -15,13 +15,13 @@
|
||||
*/
|
||||
package org.onlab.onos.net.flow;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* A list of BatchOperationEntry.
|
||||
*
|
||||
@ -88,6 +88,16 @@ public abstract class BatchOperation<T extends BatchOperationEntry<?, ?>> {
|
||||
return ops.add(entry) ? this : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all operations from another batch to this batch.
|
||||
*
|
||||
* @param another another batch
|
||||
* @return true if success
|
||||
*/
|
||||
public boolean addAll(BatchOperation<T> another) {
|
||||
return ops.addAll(another.getOperations());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
|
@ -19,12 +19,20 @@ import java.util.Set;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* Representation of a completed flow rule batch operation.
|
||||
*/
|
||||
public class CompletedBatchOperation implements BatchOperationResult<FlowRule> {
|
||||
|
||||
|
||||
private final boolean success;
|
||||
private final Set<FlowRule> failures;
|
||||
|
||||
/**
|
||||
* Creates a new batch completion result.
|
||||
*
|
||||
* @param success indicates whether the completion is successful.
|
||||
* @param failures set of any failures encountered
|
||||
*/
|
||||
public CompletedBatchOperation(boolean success, Set<? extends FlowRule> failures) {
|
||||
this.success = success;
|
||||
this.failures = ImmutableSet.copyOf(failures);
|
||||
@ -40,5 +48,4 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> {
|
||||
return failures;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -15,7 +15,10 @@
|
||||
*/
|
||||
package org.onlab.onos.net.intent;
|
||||
|
||||
import org.onlab.onos.net.resource.LinkResourceAllocations;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Abstraction of a compiler which is capable of taking an intent
|
||||
@ -27,9 +30,13 @@ public interface IntentCompiler<T extends Intent> {
|
||||
/**
|
||||
* Compiles the specified intent into other intents.
|
||||
*
|
||||
* @param intent intent to be compiled
|
||||
* @param intent intent to be compiled
|
||||
* @param installable previously compilation result; optional
|
||||
* @param resources previously allocated resources; optional
|
||||
* @return list of resulting intents
|
||||
* @throws IntentException if issues are encountered while compiling the intent
|
||||
*/
|
||||
List<Intent> compile(T intent);
|
||||
List<Intent> compile(T intent, List<Intent> installable,
|
||||
Set<LinkResourceAllocations> resources);
|
||||
|
||||
}
|
||||
|
@ -15,10 +15,10 @@
|
||||
*/
|
||||
package org.onlab.onos.net.intent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Abstraction of entity capable of installing intents to the environment.
|
||||
*/
|
||||
@ -26,8 +26,8 @@ public interface IntentInstaller<T extends Intent> {
|
||||
/**
|
||||
* Installs the specified intent to the environment.
|
||||
*
|
||||
* @param intent intent to be installed
|
||||
* @return FlowRule operations to install
|
||||
* @param intent intent to be installed
|
||||
* @return flow rule operations to complete install
|
||||
* @throws IntentException if issues are encountered while installing the intent
|
||||
*/
|
||||
List<FlowRuleBatchOperation> install(T intent);
|
||||
@ -35,9 +35,20 @@ public interface IntentInstaller<T extends Intent> {
|
||||
/**
|
||||
* Uninstalls the specified intent from the environment.
|
||||
*
|
||||
* @param intent intent to be uninstalled
|
||||
* @return FlowRule operations to uninstall
|
||||
* @param intent intent to be uninstalled
|
||||
* @return flow rule operations to complete uninstall
|
||||
* @throws IntentException if issues are encountered while uninstalling the intent
|
||||
*/
|
||||
List<FlowRuleBatchOperation> uninstall(T intent);
|
||||
|
||||
/**
|
||||
* Replaces the specified intent with a new one in the environment.
|
||||
*
|
||||
* @param oldIntent intent to be removed
|
||||
* @param newIntent intent to be installed
|
||||
* @return flow rule operations to complete the replace
|
||||
* @throws IntentException if issues are encountered while uninstalling the intent
|
||||
*/
|
||||
List<FlowRuleBatchOperation> replace(T oldIntent, T newIntent);
|
||||
|
||||
}
|
||||
|
@ -15,6 +15,11 @@
|
||||
*/
|
||||
package org.onlab.onos.net.intent;
|
||||
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.google.common.base.MoreObjects.toStringHelper;
|
||||
|
||||
/**
|
||||
* Abstraction of an intent-related operation, e.g. add, remove, replace.
|
||||
*/
|
||||
@ -27,7 +32,7 @@ public class IntentOperation {
|
||||
/**
|
||||
* Operation type.
|
||||
*/
|
||||
enum Type {
|
||||
public enum Type {
|
||||
/**
|
||||
* Indicates that an intent should be added.
|
||||
*/
|
||||
@ -41,15 +46,20 @@ public class IntentOperation {
|
||||
/**
|
||||
* Indicates that an intent should be replaced with another.
|
||||
*/
|
||||
REPLACE
|
||||
REPLACE,
|
||||
|
||||
/**
|
||||
* Indicates that an intent should be updated (i.e. recompiled/reinstalled).
|
||||
*/
|
||||
UPDATE,
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an intent operation.
|
||||
*
|
||||
* @param type operation type
|
||||
* @param type operation type
|
||||
* @param intentId identifier of the intent subject to the operation
|
||||
* @param intent intent subject
|
||||
* @param intent intent subject
|
||||
*/
|
||||
IntentOperation(Type type, IntentId intentId, Intent intent) {
|
||||
this.type = type;
|
||||
@ -85,4 +95,32 @@ public class IntentOperation {
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(type, intentId, intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final IntentOperation other = (IntentOperation) obj;
|
||||
return Objects.equals(this.type, other.type) &&
|
||||
Objects.equals(this.intentId, other.intentId) &&
|
||||
Objects.equals(this.intent, other.intent);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toStringHelper(this)
|
||||
.add("type", type)
|
||||
.add("intentId", intentId)
|
||||
.add("intent", intent)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
@ -18,11 +18,11 @@ package org.onlab.onos.net.intent;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.google.common.base.MoreObjects.toStringHelper;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static org.onlab.onos.net.intent.IntentOperation.Type.REPLACE;
|
||||
import static org.onlab.onos.net.intent.IntentOperation.Type.SUBMIT;
|
||||
import static org.onlab.onos.net.intent.IntentOperation.Type.WITHDRAW;
|
||||
import static org.onlab.onos.net.intent.IntentOperation.Type.*;
|
||||
|
||||
/**
|
||||
* Batch of intent submit/withdraw/replace operations.
|
||||
@ -58,6 +58,31 @@ public final class IntentOperations {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(operations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final IntentOperations other = (IntentOperations) obj;
|
||||
return Objects.equals(this.operations, other.operations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toStringHelper(this)
|
||||
.add("operations", operations)
|
||||
.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for batches of intent operations.
|
||||
*/
|
||||
@ -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.
|
||||
*
|
||||
|
@ -17,7 +17,6 @@ package org.onlab.onos.net.intent;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Service for application submitting or withdrawing their intents.
|
||||
@ -59,9 +58,8 @@ public interface IntentService {
|
||||
* affected at later time.
|
||||
* </p>
|
||||
* @param operations batch of intent operations
|
||||
* @return Future to get execution result
|
||||
*/
|
||||
Future<IntentOperations> execute(IntentOperations operations);
|
||||
void execute(IntentOperations operations);
|
||||
|
||||
/**
|
||||
* Returns an iterable of intents currently in the system.
|
||||
|
@ -24,7 +24,6 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Fake implementation of the intent service to assist in developing tests of
|
||||
@ -104,7 +103,7 @@ public class FakeIntentManager implements TestableIntentService {
|
||||
try {
|
||||
// For the fake, we compile using a single level pass
|
||||
List<Intent> installable = new ArrayList<>();
|
||||
for (Intent compiled : getCompiler(intent).compile(intent)) {
|
||||
for (Intent compiled : getCompiler(intent).compile(intent, null, null)) {
|
||||
installable.add((Intent) compiled);
|
||||
}
|
||||
executeInstallingPhase(intent, installable);
|
||||
@ -192,9 +191,8 @@ public class FakeIntentManager implements TestableIntentService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<IntentOperations> execute(IntentOperations operations) {
|
||||
public void execute(IntentOperations operations) {
|
||||
// TODO: implement later
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -29,11 +29,13 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
|
||||
import org.onlab.onos.net.resource.LinkResourceAllocations;
|
||||
|
||||
/**
|
||||
* Suite of tests for the intent service contract.
|
||||
@ -294,7 +296,8 @@ public class IntentServiceTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Intent> compile(TestIntent intent) {
|
||||
public List<Intent> compile(TestIntent intent, List<Intent> installable,
|
||||
Set<LinkResourceAllocations> resources) {
|
||||
if (fail) {
|
||||
throw new IntentException("compile failed by design");
|
||||
}
|
||||
@ -326,6 +329,12 @@ public class IntentServiceTest {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowRuleBatchOperation> replace(TestInstallableIntent intent,
|
||||
TestInstallableIntent newIntent) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -509,13 +509,8 @@ public class FlowRuleManager
|
||||
boolean success = true;
|
||||
Set<FlowRule> failed = Sets.newHashSet();
|
||||
CompletedBatchOperation completed;
|
||||
long start = System.nanoTime();
|
||||
long end = start + unit.toNanos(timeout);
|
||||
|
||||
for (Future<CompletedBatchOperation> future : futures) {
|
||||
long now = System.nanoTime();
|
||||
long thisTimeout = end - now;
|
||||
completed = future.get(thisTimeout, TimeUnit.NANOSECONDS);
|
||||
completed = future.get(timeout, unit);
|
||||
success = validateBatchOperation(failed, completed);
|
||||
}
|
||||
return finalizeBatchOperation(success, failed);
|
||||
|
@ -27,9 +27,11 @@ import org.onlab.onos.net.host.HostService;
|
||||
import org.onlab.onos.net.intent.HostToHostIntent;
|
||||
import org.onlab.onos.net.intent.Intent;
|
||||
import org.onlab.onos.net.intent.PathIntent;
|
||||
import org.onlab.onos.net.resource.LinkResourceAllocations;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.onlab.onos.net.flow.DefaultTrafficSelector.builder;
|
||||
|
||||
@ -54,7 +56,8 @@ public class HostToHostIntentCompiler
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Intent> compile(HostToHostIntent intent) {
|
||||
public List<Intent> compile(HostToHostIntent intent, List<Intent> installable,
|
||||
Set<LinkResourceAllocations> resources) {
|
||||
Path pathOne = getPath(intent, intent.one(), intent.two());
|
||||
Path pathTwo = getPath(intent, intent.two(), intent.one());
|
||||
|
||||
|
@ -15,31 +15,10 @@
|
||||
*/
|
||||
package org.onlab.onos.net.intent.impl;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static java.util.concurrent.Executors.newSingleThreadExecutor;
|
||||
import static org.onlab.onos.net.intent.IntentState.COMPILING;
|
||||
import static org.onlab.onos.net.intent.IntentState.FAILED;
|
||||
import static org.onlab.onos.net.intent.IntentState.INSTALLED;
|
||||
import static org.onlab.onos.net.intent.IntentState.INSTALLING;
|
||||
import static org.onlab.onos.net.intent.IntentState.RECOMPILING;
|
||||
import static org.onlab.onos.net.intent.IntentState.WITHDRAWING;
|
||||
import static org.onlab.onos.net.intent.IntentState.WITHDRAWN;
|
||||
import static org.onlab.util.Tools.namedThreads;
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import org.apache.felix.scr.annotations.Activate;
|
||||
import org.apache.felix.scr.annotations.Component;
|
||||
import org.apache.felix.scr.annotations.Deactivate;
|
||||
@ -52,6 +31,8 @@ import org.onlab.onos.net.flow.CompletedBatchOperation;
|
||||
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
|
||||
import org.onlab.onos.net.flow.FlowRuleService;
|
||||
import org.onlab.onos.net.intent.Intent;
|
||||
import org.onlab.onos.net.intent.IntentBatchDelegate;
|
||||
import org.onlab.onos.net.intent.IntentBatchService;
|
||||
import org.onlab.onos.net.intent.IntentCompiler;
|
||||
import org.onlab.onos.net.intent.IntentEvent;
|
||||
import org.onlab.onos.net.intent.IntentException;
|
||||
@ -59,6 +40,7 @@ import org.onlab.onos.net.intent.IntentExtensionService;
|
||||
import org.onlab.onos.net.intent.IntentId;
|
||||
import org.onlab.onos.net.intent.IntentInstaller;
|
||||
import org.onlab.onos.net.intent.IntentListener;
|
||||
import org.onlab.onos.net.intent.IntentOperation;
|
||||
import org.onlab.onos.net.intent.IntentOperations;
|
||||
import org.onlab.onos.net.intent.IntentService;
|
||||
import org.onlab.onos.net.intent.IntentState;
|
||||
@ -66,9 +48,24 @@ import org.onlab.onos.net.intent.IntentStore;
|
||||
import org.onlab.onos.net.intent.IntentStoreDelegate;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static java.util.concurrent.Executors.newSingleThreadExecutor;
|
||||
import static org.onlab.onos.net.intent.IntentState.*;
|
||||
import static org.onlab.util.Tools.namedThreads;
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
/**
|
||||
* An implementation of Intent Manager.
|
||||
@ -96,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,6 +111,13 @@ public class LinkCollectionIntentInstaller implements IntentInstaller<LinkCollec
|
||||
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowRuleBatchOperation> replace(LinkCollectionIntent intent,
|
||||
LinkCollectionIntent newIntent) {
|
||||
// FIXME: implement
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a FlowRuleBatchEntry based on the provided parameters.
|
||||
*
|
||||
|
@ -29,6 +29,7 @@ import org.onlab.onos.net.intent.IntentExtensionService;
|
||||
import org.onlab.onos.net.intent.LinkCollectionIntent;
|
||||
import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
|
||||
import org.onlab.onos.net.intent.PointToPointIntent;
|
||||
import org.onlab.onos.net.resource.LinkResourceAllocations;
|
||||
import org.onlab.onos.net.topology.PathService;
|
||||
|
||||
import java.util.Arrays;
|
||||
@ -61,7 +62,8 @@ public class MultiPointToSinglePointIntentCompiler
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Intent> compile(MultiPointToSinglePointIntent intent) {
|
||||
public List<Intent> compile(MultiPointToSinglePointIntent intent, List<Intent> installable,
|
||||
Set<LinkResourceAllocations> resources) {
|
||||
Set<Link> links = new HashSet<>();
|
||||
|
||||
for (ConnectPoint ingressPoint : intent.ingressPoints()) {
|
||||
|
@ -29,6 +29,7 @@ import org.onlab.onos.net.intent.IntentCompiler;
|
||||
import org.onlab.onos.net.intent.IntentExtensionService;
|
||||
import org.onlab.onos.net.intent.OpticalConnectivityIntent;
|
||||
import org.onlab.onos.net.intent.OpticalPathIntent;
|
||||
import org.onlab.onos.net.resource.LinkResourceAllocations;
|
||||
import org.onlab.onos.net.topology.LinkWeight;
|
||||
import org.onlab.onos.net.topology.Topology;
|
||||
import org.onlab.onos.net.topology.TopologyEdge;
|
||||
@ -60,7 +61,9 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Intent> compile(OpticalConnectivityIntent intent) {
|
||||
public List<Intent> compile(OpticalConnectivityIntent intent,
|
||||
List<Intent> installable,
|
||||
Set<LinkResourceAllocations> resources) {
|
||||
// TODO: compute multiple paths using the K-shortest path algorithm
|
||||
Path path = calculateOpticalPath(intent.getSrcConnectPoint(), intent.getDst());
|
||||
Intent newIntent = new OpticalPathIntent(intent.appId(),
|
||||
|
@ -104,6 +104,13 @@ public class OpticalPathIntentInstaller implements IntentInstaller<OpticalPathIn
|
||||
return generateRules(intent, allocations, FlowRuleOperation.REMOVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowRuleBatchOperation> replace(OpticalPathIntent intent,
|
||||
OpticalPathIntent newIntent) {
|
||||
// FIXME: implement this
|
||||
return null;
|
||||
}
|
||||
|
||||
private LinkResourceAllocations assignWavelength(OpticalPathIntent intent) {
|
||||
LinkResourceRequest.Builder request = DefaultLinkResourceRequest.builder(intent.id(),
|
||||
intent.path().links())
|
||||
|
@ -131,6 +131,15 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
|
||||
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowRuleBatchOperation> replace(PathIntent oldIntent, PathIntent newIntent) {
|
||||
// FIXME: implement this
|
||||
List<FlowRuleBatchOperation> batches = Lists.newArrayList();
|
||||
batches.addAll(uninstall(oldIntent));
|
||||
batches.addAll(install(newIntent));
|
||||
return batches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate resources required for an intent.
|
||||
*
|
||||
@ -147,7 +156,7 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
|
||||
return request.resources().isEmpty() ? null : resourceService.requestResources(request);
|
||||
}
|
||||
|
||||
// TODO refactor below this line... ----------------------------
|
||||
// FIXME refactor below this line... ----------------------------
|
||||
|
||||
/**
|
||||
* Generates the series of MatchActionOperations from the
|
||||
|
@ -28,9 +28,11 @@ import org.onlab.onos.net.intent.Intent;
|
||||
import org.onlab.onos.net.intent.PathIntent;
|
||||
import org.onlab.onos.net.intent.PointToPointIntent;
|
||||
import org.onlab.onos.net.provider.ProviderId;
|
||||
import org.onlab.onos.net.resource.LinkResourceAllocations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.onlab.onos.net.Link.Type.DIRECT;
|
||||
@ -57,7 +59,9 @@ public class PointToPointIntentCompiler
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Intent> compile(PointToPointIntent intent) {
|
||||
public List<Intent> compile(PointToPointIntent intent, List<Intent> installable,
|
||||
Set<LinkResourceAllocations> resources) {
|
||||
|
||||
ConnectPoint ingressPoint = intent.ingressPoint();
|
||||
ConnectPoint egressPoint = intent.egressPoint();
|
||||
|
||||
|
@ -87,7 +87,7 @@ public class PathConstraintCalculationTest {
|
||||
constraints);
|
||||
final PointToPointIntentCompiler compiler = makeCompiler(resourceService);
|
||||
|
||||
return compiler.compile(intent);
|
||||
return compiler.compile(intent, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -121,7 +121,7 @@ public class TestHostToHostIntentCompiler {
|
||||
HostToHostIntentCompiler compiler = makeCompiler(hops);
|
||||
assertThat(compiler, is(notNullValue()));
|
||||
|
||||
List<Intent> result = compiler.compile(intent);
|
||||
List<Intent> result = compiler.compile(intent, null, null);
|
||||
assertThat(result, is(Matchers.notNullValue()));
|
||||
assertThat(result, hasSize(2));
|
||||
Intent forwardResultIntent = result.get(0);
|
||||
|
@ -137,7 +137,7 @@ public class TestMultiPointToSinglePointIntentCompiler {
|
||||
MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
|
||||
assertThat(compiler, is(notNullValue()));
|
||||
|
||||
List<Intent> result = compiler.compile(intent);
|
||||
List<Intent> result = compiler.compile(intent, null, null);
|
||||
assertThat(result, is(Matchers.notNullValue()));
|
||||
assertThat(result, hasSize(1));
|
||||
Intent resultIntent = result.get(0);
|
||||
@ -172,7 +172,7 @@ public class TestMultiPointToSinglePointIntentCompiler {
|
||||
MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
|
||||
assertThat(compiler, is(notNullValue()));
|
||||
|
||||
List<Intent> result = compiler.compile(intent);
|
||||
List<Intent> result = compiler.compile(intent, null, null);
|
||||
assertThat(result, is(notNullValue()));
|
||||
assertThat(result, hasSize(1));
|
||||
Intent resultIntent = result.get(0);
|
||||
@ -205,7 +205,7 @@ public class TestMultiPointToSinglePointIntentCompiler {
|
||||
MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
|
||||
assertThat(compiler, is(notNullValue()));
|
||||
|
||||
List<Intent> result = compiler.compile(intent);
|
||||
List<Intent> result = compiler.compile(intent, null, null);
|
||||
assertThat(result, is(notNullValue()));
|
||||
assertThat(result, hasSize(1));
|
||||
Intent resultIntent = result.get(0);
|
||||
|
@ -93,7 +93,7 @@ public class TestPointToPointIntentCompiler {
|
||||
PointToPointIntentCompiler compiler = makeCompiler(hops);
|
||||
assertThat(compiler, is(notNullValue()));
|
||||
|
||||
List<Intent> result = compiler.compile(intent);
|
||||
List<Intent> result = compiler.compile(intent, null, null);
|
||||
assertThat(result, is(Matchers.notNullValue()));
|
||||
assertThat(result, hasSize(1));
|
||||
Intent forwardResultIntent = result.get(0);
|
||||
@ -126,7 +126,7 @@ public class TestPointToPointIntentCompiler {
|
||||
PointToPointIntentCompiler compiler = makeCompiler(hops);
|
||||
assertThat(compiler, is(notNullValue()));
|
||||
|
||||
List<Intent> result = compiler.compile(intent);
|
||||
List<Intent> result = compiler.compile(intent, null, null);
|
||||
assertThat(result, is(Matchers.notNullValue()));
|
||||
assertThat(result, hasSize(1));
|
||||
Intent reverseResultIntent = result.get(0);
|
||||
@ -157,7 +157,7 @@ public class TestPointToPointIntentCompiler {
|
||||
String[] hops = {"1"};
|
||||
PointToPointIntentCompiler sut = makeCompiler(hops);
|
||||
|
||||
List<Intent> compiled = sut.compile(intent);
|
||||
List<Intent> compiled = sut.compile(intent, null, null);
|
||||
|
||||
assertThat(compiled, hasSize(1));
|
||||
assertThat(compiled.get(0), is(instanceOf(PathIntent.class)));
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user