mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-10-18 02:41:49 +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;
|
||||||
import org.onlab.onos.net.intent.IntentEvent.Type;
|
import org.onlab.onos.net.intent.IntentEvent.Type;
|
||||||
import org.onlab.onos.net.intent.IntentListener;
|
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.IntentService;
|
||||||
import org.onlab.onos.net.intent.PointToPointIntent;
|
import org.onlab.onos.net.intent.PointToPointIntent;
|
||||||
import org.onlab.packet.Ethernet;
|
import org.onlab.packet.Ethernet;
|
||||||
@ -63,9 +64,6 @@ public class IntentPushTestCommand extends AbstractShellCommand
|
|||||||
required = true, multiValued = false)
|
required = true, multiValued = false)
|
||||||
String countString = null;
|
String countString = null;
|
||||||
|
|
||||||
|
|
||||||
private static long id = 0x7870001;
|
|
||||||
|
|
||||||
private IntentService service;
|
private IntentService service;
|
||||||
private CountDownLatch latch;
|
private CountDownLatch latch;
|
||||||
private long start, end;
|
private long start, end;
|
||||||
@ -91,15 +89,18 @@ public class IntentPushTestCommand extends AbstractShellCommand
|
|||||||
service.addListener(this);
|
service.addListener(this);
|
||||||
latch = new CountDownLatch(count);
|
latch = new CountDownLatch(count);
|
||||||
|
|
||||||
start = System.currentTimeMillis();
|
IntentOperations.Builder ops = IntentOperations.builder();
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 1; i <= count; i++) {
|
||||||
TrafficSelector s = selector
|
TrafficSelector s = selector
|
||||||
.matchEthSrc(MacAddress.valueOf(i))
|
.matchEthSrc(MacAddress.valueOf(i))
|
||||||
.build();
|
.build();
|
||||||
Intent intent = new PointToPointIntent(appId(), s, treatment,
|
Intent intent = new PointToPointIntent(appId(), s, treatment,
|
||||||
ingress, egress);
|
ingress, egress);
|
||||||
service.submit(intent);
|
ops.addSubmitOperation(intent);
|
||||||
}
|
}
|
||||||
|
IntentOperations operations = ops.build();
|
||||||
|
start = System.currentTimeMillis();
|
||||||
|
service.execute(operations);
|
||||||
try {
|
try {
|
||||||
if (latch.await(10, TimeUnit.SECONDS)) {
|
if (latch.await(10, TimeUnit.SECONDS)) {
|
||||||
printResults(count);
|
printResults(count);
|
||||||
|
@ -15,13 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.onlab.onos.net.flow;
|
package org.onlab.onos.net.flow;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of BatchOperationEntry.
|
* A list of BatchOperationEntry.
|
||||||
*
|
*
|
||||||
@ -88,6 +88,16 @@ public abstract class BatchOperation<T extends BatchOperationEntry<?, ?>> {
|
|||||||
return ops.add(entry) ? this : null;
|
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
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) {
|
if (this == o) {
|
||||||
|
@ -19,12 +19,20 @@ import java.util.Set;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of a completed flow rule batch operation.
|
||||||
|
*/
|
||||||
public class CompletedBatchOperation implements BatchOperationResult<FlowRule> {
|
public class CompletedBatchOperation implements BatchOperationResult<FlowRule> {
|
||||||
|
|
||||||
|
|
||||||
private final boolean success;
|
private final boolean success;
|
||||||
private final Set<FlowRule> failures;
|
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) {
|
public CompletedBatchOperation(boolean success, Set<? extends FlowRule> failures) {
|
||||||
this.success = success;
|
this.success = success;
|
||||||
this.failures = ImmutableSet.copyOf(failures);
|
this.failures = ImmutableSet.copyOf(failures);
|
||||||
@ -40,5 +48,4 @@ public class CompletedBatchOperation implements BatchOperationResult<FlowRule> {
|
|||||||
return failures;
|
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;
|
package org.onlab.onos.net.intent;
|
||||||
|
|
||||||
|
import org.onlab.onos.net.resource.LinkResourceAllocations;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstraction of a compiler which is capable of taking an intent
|
* 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.
|
* 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
|
* @return list of resulting intents
|
||||||
* @throws IntentException if issues are encountered while compiling the intent
|
* @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;
|
package org.onlab.onos.net.intent;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
|
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstraction of entity capable of installing intents to the environment.
|
* 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.
|
* Installs the specified intent to the environment.
|
||||||
*
|
*
|
||||||
* @param intent intent to be installed
|
* @param intent intent to be installed
|
||||||
* @return FlowRule operations to install
|
* @return flow rule operations to complete install
|
||||||
* @throws IntentException if issues are encountered while installing the intent
|
* @throws IntentException if issues are encountered while installing the intent
|
||||||
*/
|
*/
|
||||||
List<FlowRuleBatchOperation> install(T intent);
|
List<FlowRuleBatchOperation> install(T intent);
|
||||||
@ -35,9 +35,20 @@ public interface IntentInstaller<T extends Intent> {
|
|||||||
/**
|
/**
|
||||||
* Uninstalls the specified intent from the environment.
|
* Uninstalls the specified intent from the environment.
|
||||||
*
|
*
|
||||||
* @param intent intent to be uninstalled
|
* @param intent intent to be uninstalled
|
||||||
* @return FlowRule operations to uninstall
|
* @return flow rule operations to complete uninstall
|
||||||
* @throws IntentException if issues are encountered while uninstalling the intent
|
* @throws IntentException if issues are encountered while uninstalling the intent
|
||||||
*/
|
*/
|
||||||
List<FlowRuleBatchOperation> uninstall(T 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;
|
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.
|
* Abstraction of an intent-related operation, e.g. add, remove, replace.
|
||||||
*/
|
*/
|
||||||
@ -27,7 +32,7 @@ public class IntentOperation {
|
|||||||
/**
|
/**
|
||||||
* Operation type.
|
* Operation type.
|
||||||
*/
|
*/
|
||||||
enum Type {
|
public enum Type {
|
||||||
/**
|
/**
|
||||||
* Indicates that an intent should be added.
|
* Indicates that an intent should be added.
|
||||||
*/
|
*/
|
||||||
@ -41,15 +46,20 @@ public class IntentOperation {
|
|||||||
/**
|
/**
|
||||||
* Indicates that an intent should be replaced with another.
|
* 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.
|
* Creates an intent operation.
|
||||||
*
|
*
|
||||||
* @param type operation type
|
* @param type operation type
|
||||||
* @param intentId identifier of the intent subject to the operation
|
* @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) {
|
IntentOperation(Type type, IntentId intentId, Intent intent) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
@ -85,4 +95,32 @@ public class IntentOperation {
|
|||||||
return intent;
|
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 com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
import java.util.List;
|
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 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.*;
|
||||||
import static org.onlab.onos.net.intent.IntentOperation.Type.SUBMIT;
|
|
||||||
import static org.onlab.onos.net.intent.IntentOperation.Type.WITHDRAW;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Batch of intent submit/withdraw/replace operations.
|
* Batch of intent submit/withdraw/replace operations.
|
||||||
@ -58,6 +58,31 @@ public final class IntentOperations {
|
|||||||
return new Builder();
|
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.
|
* Builder for batches of intent operations.
|
||||||
*/
|
*/
|
||||||
@ -107,6 +132,18 @@ public final class IntentOperations {
|
|||||||
return this;
|
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.
|
* Builds a batch of intent operations.
|
||||||
*
|
*
|
||||||
|
@ -17,7 +17,6 @@ package org.onlab.onos.net.intent;
|
|||||||
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for application submitting or withdrawing their intents.
|
* Service for application submitting or withdrawing their intents.
|
||||||
@ -59,9 +58,8 @@ public interface IntentService {
|
|||||||
* affected at later time.
|
* affected at later time.
|
||||||
* </p>
|
* </p>
|
||||||
* @param operations batch of intent operations
|
* @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.
|
* Returns an iterable of intents currently in the system.
|
||||||
|
@ -24,7 +24,6 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fake implementation of the intent service to assist in developing tests of
|
* Fake implementation of the intent service to assist in developing tests of
|
||||||
@ -104,7 +103,7 @@ public class FakeIntentManager implements TestableIntentService {
|
|||||||
try {
|
try {
|
||||||
// For the fake, we compile using a single level pass
|
// For the fake, we compile using a single level pass
|
||||||
List<Intent> installable = new ArrayList<>();
|
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);
|
installable.add((Intent) compiled);
|
||||||
}
|
}
|
||||||
executeInstallingPhase(intent, installable);
|
executeInstallingPhase(intent, installable);
|
||||||
@ -192,9 +191,8 @@ public class FakeIntentManager implements TestableIntentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Future<IntentOperations> execute(IntentOperations operations) {
|
public void execute(IntentOperations operations) {
|
||||||
// TODO: implement later
|
// TODO: implement later
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -29,11 +29,13 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
|
import org.onlab.onos.net.flow.FlowRuleBatchOperation;
|
||||||
|
import org.onlab.onos.net.resource.LinkResourceAllocations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Suite of tests for the intent service contract.
|
* Suite of tests for the intent service contract.
|
||||||
@ -294,7 +296,8 @@ public class IntentServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Intent> compile(TestIntent intent) {
|
public List<Intent> compile(TestIntent intent, List<Intent> installable,
|
||||||
|
Set<LinkResourceAllocations> resources) {
|
||||||
if (fail) {
|
if (fail) {
|
||||||
throw new IntentException("compile failed by design");
|
throw new IntentException("compile failed by design");
|
||||||
}
|
}
|
||||||
@ -326,6 +329,12 @@ public class IntentServiceTest {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<FlowRuleBatchOperation> replace(TestInstallableIntent intent,
|
||||||
|
TestInstallableIntent newIntent) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -509,13 +509,8 @@ public class FlowRuleManager
|
|||||||
boolean success = true;
|
boolean success = true;
|
||||||
Set<FlowRule> failed = Sets.newHashSet();
|
Set<FlowRule> failed = Sets.newHashSet();
|
||||||
CompletedBatchOperation completed;
|
CompletedBatchOperation completed;
|
||||||
long start = System.nanoTime();
|
|
||||||
long end = start + unit.toNanos(timeout);
|
|
||||||
|
|
||||||
for (Future<CompletedBatchOperation> future : futures) {
|
for (Future<CompletedBatchOperation> future : futures) {
|
||||||
long now = System.nanoTime();
|
completed = future.get(timeout, unit);
|
||||||
long thisTimeout = end - now;
|
|
||||||
completed = future.get(thisTimeout, TimeUnit.NANOSECONDS);
|
|
||||||
success = validateBatchOperation(failed, completed);
|
success = validateBatchOperation(failed, completed);
|
||||||
}
|
}
|
||||||
return finalizeBatchOperation(success, failed);
|
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.HostToHostIntent;
|
||||||
import org.onlab.onos.net.intent.Intent;
|
import org.onlab.onos.net.intent.Intent;
|
||||||
import org.onlab.onos.net.intent.PathIntent;
|
import org.onlab.onos.net.intent.PathIntent;
|
||||||
|
import org.onlab.onos.net.resource.LinkResourceAllocations;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.onlab.onos.net.flow.DefaultTrafficSelector.builder;
|
import static org.onlab.onos.net.flow.DefaultTrafficSelector.builder;
|
||||||
|
|
||||||
@ -54,7 +56,8 @@ public class HostToHostIntentCompiler
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 pathOne = getPath(intent, intent.one(), intent.two());
|
||||||
Path pathTwo = getPath(intent, intent.two(), intent.one());
|
Path pathTwo = getPath(intent, intent.two(), intent.one());
|
||||||
|
|
||||||
|
@ -15,31 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.onlab.onos.net.intent.impl;
|
package org.onlab.onos.net.intent.impl;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import com.google.common.collect.ImmutableList;
|
||||||
import static java.util.concurrent.Executors.newSingleThreadExecutor;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import static org.onlab.onos.net.intent.IntentState.COMPILING;
|
import com.google.common.collect.Lists;
|
||||||
import static org.onlab.onos.net.intent.IntentState.FAILED;
|
import com.google.common.collect.Maps;
|
||||||
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 org.apache.felix.scr.annotations.Activate;
|
import org.apache.felix.scr.annotations.Activate;
|
||||||
import org.apache.felix.scr.annotations.Component;
|
import org.apache.felix.scr.annotations.Component;
|
||||||
import org.apache.felix.scr.annotations.Deactivate;
|
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.FlowRuleBatchOperation;
|
||||||
import org.onlab.onos.net.flow.FlowRuleService;
|
import org.onlab.onos.net.flow.FlowRuleService;
|
||||||
import org.onlab.onos.net.intent.Intent;
|
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.IntentCompiler;
|
||||||
import org.onlab.onos.net.intent.IntentEvent;
|
import org.onlab.onos.net.intent.IntentEvent;
|
||||||
import org.onlab.onos.net.intent.IntentException;
|
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.IntentId;
|
||||||
import org.onlab.onos.net.intent.IntentInstaller;
|
import org.onlab.onos.net.intent.IntentInstaller;
|
||||||
import org.onlab.onos.net.intent.IntentListener;
|
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.IntentOperations;
|
||||||
import org.onlab.onos.net.intent.IntentService;
|
import org.onlab.onos.net.intent.IntentService;
|
||||||
import org.onlab.onos.net.intent.IntentState;
|
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.onlab.onos.net.intent.IntentStoreDelegate;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import java.util.ArrayList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import java.util.List;
|
||||||
import com.google.common.collect.Lists;
|
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.
|
* An implementation of Intent Manager.
|
||||||
@ -96,10 +93,14 @@ public class IntentManager
|
|||||||
|
|
||||||
private final IntentStoreDelegate delegate = new InternalStoreDelegate();
|
private final IntentStoreDelegate delegate = new InternalStoreDelegate();
|
||||||
private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
|
private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
|
||||||
|
private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
|
||||||
|
|
||||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||||
protected IntentStore store;
|
protected IntentStore store;
|
||||||
|
|
||||||
|
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||||
|
protected IntentBatchService batchService;
|
||||||
|
|
||||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||||
protected ObjectiveTrackerService trackerService;
|
protected ObjectiveTrackerService trackerService;
|
||||||
|
|
||||||
@ -113,6 +114,7 @@ public class IntentManager
|
|||||||
public void activate() {
|
public void activate() {
|
||||||
store.setDelegate(delegate);
|
store.setDelegate(delegate);
|
||||||
trackerService.setDelegate(topoDelegate);
|
trackerService.setDelegate(topoDelegate);
|
||||||
|
batchService.setDelegate(batchDelegate);
|
||||||
eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
|
eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
|
||||||
executor = newSingleThreadExecutor(namedThreads("onos-intents"));
|
executor = newSingleThreadExecutor(namedThreads("onos-intents"));
|
||||||
monitorExecutor = newSingleThreadExecutor(namedThreads("onos-intent-monitor"));
|
monitorExecutor = newSingleThreadExecutor(namedThreads("onos-intent-monitor"));
|
||||||
@ -123,6 +125,7 @@ public class IntentManager
|
|||||||
public void deactivate() {
|
public void deactivate() {
|
||||||
store.unsetDelegate(delegate);
|
store.unsetDelegate(delegate);
|
||||||
trackerService.unsetDelegate(topoDelegate);
|
trackerService.unsetDelegate(topoDelegate);
|
||||||
|
batchService.unsetDelegate(batchDelegate);
|
||||||
eventDispatcher.removeSink(IntentEvent.class);
|
eventDispatcher.removeSink(IntentEvent.class);
|
||||||
executor.shutdown();
|
executor.shutdown();
|
||||||
monitorExecutor.shutdown();
|
monitorExecutor.shutdown();
|
||||||
@ -132,30 +135,27 @@ public class IntentManager
|
|||||||
@Override
|
@Override
|
||||||
public void submit(Intent intent) {
|
public void submit(Intent intent) {
|
||||||
checkNotNull(intent, INTENT_NULL);
|
checkNotNull(intent, INTENT_NULL);
|
||||||
registerSubclassCompilerIfNeeded(intent);
|
execute(IntentOperations.builder().addSubmitOperation(intent).build());
|
||||||
IntentEvent event = store.createIntent(intent);
|
|
||||||
if (event != null) {
|
|
||||||
eventDispatcher.post(event);
|
|
||||||
executor.execute(new IntentTask(COMPILING, intent));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void withdraw(Intent intent) {
|
public void withdraw(Intent intent) {
|
||||||
checkNotNull(intent, INTENT_NULL);
|
checkNotNull(intent, INTENT_NULL);
|
||||||
executor.execute(new IntentTask(WITHDRAWING, intent));
|
execute(IntentOperations.builder().addWithdrawOperation(intent.id()).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: implement this method
|
|
||||||
@Override
|
@Override
|
||||||
public void replace(IntentId oldIntentId, Intent newIntent) {
|
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
|
@Override
|
||||||
public Future<IntentOperations> execute(IntentOperations operations) {
|
public void execute(IntentOperations operations) {
|
||||||
throw new UnsupportedOperationException("execute() is not implemented yet");
|
batchService.addIntentOperations(operations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -261,29 +261,25 @@ public class IntentManager
|
|||||||
/**
|
/**
|
||||||
* Compiles the specified intent.
|
* 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.
|
// Indicate that the intent is entering the compiling phase.
|
||||||
store.setState(intent, COMPILING);
|
update.setState(intent, COMPILING);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Compile the intent into installable derivatives.
|
// 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
|
// If all went well, associate the resulting list of installable
|
||||||
// intents with the top-level intent and proceed to install.
|
// intents with the top-level intent and proceed to install.
|
||||||
store.setInstallableIntents(intent.id(), installable);
|
update.setInstallables(installables);
|
||||||
executeInstallingPhase(intent);
|
} catch (IntentException e) {
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("Unable to compile intent {} due to:", intent.id(), e);
|
log.warn("Unable to compile intent {} due to:", intent.id(), e);
|
||||||
|
|
||||||
// If compilation failed, mark the intent as failed.
|
// If compilation failed, mark the intent as failed.
|
||||||
IntentEvent event = store.setState(intent, FAILED);
|
update.setState(intent, FAILED);
|
||||||
if (event != null) {
|
|
||||||
eventDispatcher.post(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,17 +289,18 @@ public class IntentManager
|
|||||||
* @param intent intent
|
* @param intent intent
|
||||||
* @return result of compilation
|
* @return result of compilation
|
||||||
*/
|
*/
|
||||||
private List<Intent> compileIntent(Intent intent) {
|
private List<Intent> compileIntent(Intent intent, IntentUpdate update) {
|
||||||
if (intent.isInstallable()) {
|
if (intent.isInstallable()) {
|
||||||
return ImmutableList.of(intent);
|
return ImmutableList.of(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerSubclassCompilerIfNeeded(intent);
|
||||||
|
List<Intent> previous = update.oldInstallables();
|
||||||
|
// FIXME: get previous resources
|
||||||
List<Intent> installable = new ArrayList<>();
|
List<Intent> installable = new ArrayList<>();
|
||||||
// TODO do we need to registerSubclassCompiler?
|
for (Intent compiled : getCompiler(intent).compile(intent, previous, null)) {
|
||||||
for (Intent compiled : getCompiler(intent).compile(intent)) {
|
installable.addAll(compileIntent(compiled, update));
|
||||||
installable.addAll(compileIntent(compiled));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return installable;
|
return installable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,63 +308,110 @@ public class IntentManager
|
|||||||
* Installs all installable intents associated with the specified top-level
|
* Installs all installable intents associated with the specified top-level
|
||||||
* intent.
|
* intent.
|
||||||
*
|
*
|
||||||
* @param intent intent to be installed
|
* @param update intent update
|
||||||
*/
|
*/
|
||||||
private void executeInstallingPhase(Intent intent) {
|
private void executeInstallingPhase(IntentUpdate update) {
|
||||||
// Indicate that the intent is entering the installing phase.
|
if (update.newInstallables() == null) {
|
||||||
store.setState(intent, INSTALLING);
|
//no failed intents allowed past this point...
|
||||||
|
return;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
// 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.
|
* 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.
|
// Indicate that the intent is entering the recompiling phase.
|
||||||
store.setState(intent, RECOMPILING);
|
store.setState(intent, RECOMPILING);
|
||||||
|
|
||||||
|
List<FlowRuleBatchOperation> batches = Lists.newArrayList();
|
||||||
try {
|
try {
|
||||||
// Compile the intent into installable derivatives.
|
// 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
|
// If all went well, compare the existing list of installable
|
||||||
// intents with the newly compiled list. If they are the same,
|
// intents with the newly compiled list. If they are the same,
|
||||||
// bail, out since the previous approach was determined not to
|
// bail, out since the previous approach was determined not to
|
||||||
// be viable.
|
// be viable.
|
||||||
|
// FIXME do we need this?
|
||||||
List<Intent> originalInstallable = store.getInstallableIntents(intent.id());
|
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)) {
|
if (Objects.equals(originalInstallable, installable)) {
|
||||||
eventDispatcher.post(store.setState(intent, FAILED));
|
eventDispatcher.post(store.setState(intent, FAILED));
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, re-associate the newly compiled installable intents
|
// Otherwise, re-associate the newly compiled installable intents
|
||||||
// with the top-level intent and kick off installing phase.
|
// with the top-level intent and kick off installing phase.
|
||||||
store.setInstallableIntents(intent.id(), installable);
|
store.setInstallableIntents(intent.id(), installable);
|
||||||
executeInstallingPhase(intent);
|
// FIXME commented out for now
|
||||||
|
//batches.addAll(executeInstallingPhase(update));
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("Unable to recompile intent {} due to:", intent.id(), 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
|
* Withdraws the old intent and installs the new intent as one operation.
|
||||||
* installable derivatives.
|
|
||||||
*
|
*
|
||||||
* @param intent intent to be installed
|
* @param update intent update
|
||||||
*/
|
*/
|
||||||
private void executeWithdrawingPhase(Intent intent) {
|
private void executeReplacementPhase(IntentUpdate update) {
|
||||||
// Indicate that the intent is being withdrawn.
|
checkArgument(update.oldInstallables().size() == update.newInstallables().size(),
|
||||||
store.setState(intent, WITHDRAWING);
|
"Old and New Intent must have equivalent installable intents.");
|
||||||
uninstallIntent(intent, WITHDRAWN);
|
if (!update.oldIntent().equals(update.newIntent())) {
|
||||||
|
// only set the old intent's state if it is different
|
||||||
// If all went well, disassociate the top-level intent with its
|
update.setState(update.oldIntent(), WITHDRAWING);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
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
|
@Override
|
||||||
public void notify(IntentEvent event) {
|
public void notify(IntentEvent event) {
|
||||||
eventDispatcher.post(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,
|
public void triggerCompile(Iterable<IntentId> intentIds,
|
||||||
boolean compileAllFailed) {
|
boolean compileAllFailed) {
|
||||||
// Attempt recompilation of the specified intents first.
|
// Attempt recompilation of the specified intents first.
|
||||||
for (IntentId intentId : intentIds) {
|
IntentOperations.Builder builder = IntentOperations.builder();
|
||||||
Intent intent = getIntent(intentId);
|
for (IntentId id : intentIds) {
|
||||||
uninstallIntent(intent, RECOMPILING);
|
builder.addUpdateOperation(id);
|
||||||
|
|
||||||
//FIXME
|
|
||||||
//executeRecompilingPhase(intent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compileAllFailed) {
|
if (compileAllFailed) {
|
||||||
// If required, compile all currently failed intents.
|
// If required, compile all currently failed intents.
|
||||||
for (Intent intent : getIntents()) {
|
for (Intent intent : getIntents()) {
|
||||||
if (getIntentState(intent.id()) == FAILED) {
|
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.
|
// Auxiliary runnable to perform asynchronous tasks.
|
||||||
private class IntentTask implements Runnable {
|
private class IntentTask implements Runnable {
|
||||||
private final IntentState state;
|
private final IntentOperations operations;
|
||||||
private final Intent intent;
|
|
||||||
|
|
||||||
public IntentTask(IntentState state, Intent intent) {
|
public IntentTask(IntentOperations operations) {
|
||||||
this.state = state;
|
this.operations = operations;
|
||||||
this.intent = intent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (state == COMPILING) {
|
Map<IntentOperation, IntentUpdate> intentUpdates = Maps.newHashMap();
|
||||||
executeCompilingPhase(intent);
|
for (IntentOperation op : operations.operations()) {
|
||||||
} else if (state == RECOMPILING) {
|
intentUpdates.put(op, processIntentOperation(op));
|
||||||
executeRecompilingPhase(intent);
|
|
||||||
} else if (state == WITHDRAWING) {
|
|
||||||
executeWithdrawingPhase(intent);
|
|
||||||
}
|
}
|
||||||
|
List<FlowRuleBatchOperation> batches = mergeBatches(intentUpdates);
|
||||||
|
monitorExecutor.execute(new IntentInstallMonitor(operations, intentUpdates, batches));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class IntentInstallMonitor implements Runnable {
|
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<FlowRuleBatchOperation> work;
|
||||||
private final List<Future<CompletedBatchOperation>> futures;
|
private Future<CompletedBatchOperation> future;
|
||||||
private final IntentState nextState;
|
private final long startTime = System.currentTimeMillis();
|
||||||
|
private final long endTime = startTime + TIMEOUT;
|
||||||
|
|
||||||
public IntentInstallMonitor(Intent intent,
|
public IntentInstallMonitor(IntentOperations ops,
|
||||||
List<FlowRuleBatchOperation> work,
|
Map<IntentOperation, IntentUpdate> intentUpdateMap,
|
||||||
IntentState nextState) {
|
List<FlowRuleBatchOperation> work) {
|
||||||
this.intent = intent;
|
this.ops = ops;
|
||||||
|
this.intentUpdateMap = intentUpdateMap;
|
||||||
this.work = work;
|
this.work = work;
|
||||||
// TODO how many Futures can be outstanding? one?
|
future = applyNextBatch();
|
||||||
this.futures = Lists.newLinkedList();
|
|
||||||
this.nextState = nextState;
|
|
||||||
|
|
||||||
// TODO need to kick off the first batch sometime, why not now?
|
|
||||||
futures.add(applyNextBatch());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the intent store with the next status for this intent.
|
* Applies the next batch, and returns the future.
|
||||||
*/
|
*
|
||||||
private void updateIntent() {
|
* @return Future for next batch
|
||||||
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.
|
|
||||||
*/
|
*/
|
||||||
private Future<CompletedBatchOperation> applyNextBatch() {
|
private Future<CompletedBatchOperation> applyNextBatch() {
|
||||||
if (work.isEmpty()) {
|
if (work.isEmpty()) {
|
||||||
@ -571,46 +744,125 @@ public class IntentManager
|
|||||||
return flowRuleService.applyBatch(batch);
|
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.
|
* Iterate through the pending futures, and remove them when they have completed.
|
||||||
*/
|
*/
|
||||||
private void processFutures() {
|
private void processFutures() {
|
||||||
List<Future<CompletedBatchOperation>> newFutures = Lists.newArrayList();
|
if (future == null) {
|
||||||
for (Iterator<Future<CompletedBatchOperation>> i = futures.iterator(); i.hasNext();) {
|
return; //FIXME look at this
|
||||||
Future<CompletedBatchOperation> future = i.next();
|
}
|
||||||
try {
|
try {
|
||||||
// TODO: we may want to get the future here and go back to the future.
|
CompletedBatchOperation completed = future.get(100, TimeUnit.NANOSECONDS);
|
||||||
CompletedBatchOperation completed = future.get(100, TimeUnit.NANOSECONDS);
|
if (completed.isSuccess()) {
|
||||||
if (completed.isSuccess()) {
|
future = applyNextBatch();
|
||||||
Future<CompletedBatchOperation> newFuture = applyNextBatch();
|
} else {
|
||||||
if (newFuture != null) {
|
// TODO check if future succeeded and if not report fail items
|
||||||
// we'll add this later so that we don't get a ConcurrentModException
|
log.warn("Failed items: {}", completed.failedItems());
|
||||||
newFutures.add(newFuture);
|
// FIXME revert.... by submitting a new batch
|
||||||
}
|
//uninstallIntent(intent, RECOMPILING);
|
||||||
} else {
|
}
|
||||||
// TODO check if future succeeded and if not report fail items
|
} catch (TimeoutException | InterruptedException | ExecutionException te) {
|
||||||
log.warn("Failed items: {}", completed.failedItems());
|
//TODO look into error message
|
||||||
// TODO revert....
|
log.debug("Intallations of intent {} is still pending", ops);
|
||||||
//uninstallIntent(intent, RECOMPILING);
|
|
||||||
}
|
|
||||||
i.remove();
|
|
||||||
} catch (TimeoutException | InterruptedException | ExecutionException te) {
|
|
||||||
log.debug("Intallations of intent {} is still pending", intent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
futures.addAll(newFutures);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
processFutures();
|
processFutures();
|
||||||
if (futures.isEmpty()) {
|
if (future == null) {
|
||||||
// woohoo! we are done!
|
// 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 {
|
} else {
|
||||||
// resubmit ourselves if we are not done yet
|
// resubmit ourselves if we are not done yet
|
||||||
monitorExecutor.submit(this);
|
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));
|
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.
|
* 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.LinkCollectionIntent;
|
||||||
import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
|
import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
|
||||||
import org.onlab.onos.net.intent.PointToPointIntent;
|
import org.onlab.onos.net.intent.PointToPointIntent;
|
||||||
|
import org.onlab.onos.net.resource.LinkResourceAllocations;
|
||||||
import org.onlab.onos.net.topology.PathService;
|
import org.onlab.onos.net.topology.PathService;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -61,7 +62,8 @@ public class MultiPointToSinglePointIntentCompiler
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Intent> compile(MultiPointToSinglePointIntent intent) {
|
public List<Intent> compile(MultiPointToSinglePointIntent intent, List<Intent> installable,
|
||||||
|
Set<LinkResourceAllocations> resources) {
|
||||||
Set<Link> links = new HashSet<>();
|
Set<Link> links = new HashSet<>();
|
||||||
|
|
||||||
for (ConnectPoint ingressPoint : intent.ingressPoints()) {
|
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.IntentExtensionService;
|
||||||
import org.onlab.onos.net.intent.OpticalConnectivityIntent;
|
import org.onlab.onos.net.intent.OpticalConnectivityIntent;
|
||||||
import org.onlab.onos.net.intent.OpticalPathIntent;
|
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.LinkWeight;
|
||||||
import org.onlab.onos.net.topology.Topology;
|
import org.onlab.onos.net.topology.Topology;
|
||||||
import org.onlab.onos.net.topology.TopologyEdge;
|
import org.onlab.onos.net.topology.TopologyEdge;
|
||||||
@ -60,7 +61,9 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
// TODO: compute multiple paths using the K-shortest path algorithm
|
||||||
Path path = calculateOpticalPath(intent.getSrcConnectPoint(), intent.getDst());
|
Path path = calculateOpticalPath(intent.getSrcConnectPoint(), intent.getDst());
|
||||||
Intent newIntent = new OpticalPathIntent(intent.appId(),
|
Intent newIntent = new OpticalPathIntent(intent.appId(),
|
||||||
|
@ -104,6 +104,13 @@ public class OpticalPathIntentInstaller implements IntentInstaller<OpticalPathIn
|
|||||||
return generateRules(intent, allocations, FlowRuleOperation.REMOVE);
|
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) {
|
private LinkResourceAllocations assignWavelength(OpticalPathIntent intent) {
|
||||||
LinkResourceRequest.Builder request = DefaultLinkResourceRequest.builder(intent.id(),
|
LinkResourceRequest.Builder request = DefaultLinkResourceRequest.builder(intent.id(),
|
||||||
intent.path().links())
|
intent.path().links())
|
||||||
|
@ -131,6 +131,15 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
|
|||||||
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
|
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.
|
* Allocate resources required for an intent.
|
||||||
*
|
*
|
||||||
@ -147,7 +156,7 @@ public class PathIntentInstaller implements IntentInstaller<PathIntent> {
|
|||||||
return request.resources().isEmpty() ? null : resourceService.requestResources(request);
|
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
|
* 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.PathIntent;
|
||||||
import org.onlab.onos.net.intent.PointToPointIntent;
|
import org.onlab.onos.net.intent.PointToPointIntent;
|
||||||
import org.onlab.onos.net.provider.ProviderId;
|
import org.onlab.onos.net.provider.ProviderId;
|
||||||
|
import org.onlab.onos.net.resource.LinkResourceAllocations;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
import static org.onlab.onos.net.Link.Type.DIRECT;
|
import static org.onlab.onos.net.Link.Type.DIRECT;
|
||||||
@ -57,7 +59,9 @@ public class PointToPointIntentCompiler
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Intent> compile(PointToPointIntent intent) {
|
public List<Intent> compile(PointToPointIntent intent, List<Intent> installable,
|
||||||
|
Set<LinkResourceAllocations> resources) {
|
||||||
|
|
||||||
ConnectPoint ingressPoint = intent.ingressPoint();
|
ConnectPoint ingressPoint = intent.ingressPoint();
|
||||||
ConnectPoint egressPoint = intent.egressPoint();
|
ConnectPoint egressPoint = intent.egressPoint();
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ public class PathConstraintCalculationTest {
|
|||||||
constraints);
|
constraints);
|
||||||
final PointToPointIntentCompiler compiler = makeCompiler(resourceService);
|
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);
|
HostToHostIntentCompiler compiler = makeCompiler(hops);
|
||||||
assertThat(compiler, is(notNullValue()));
|
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, is(Matchers.notNullValue()));
|
||||||
assertThat(result, hasSize(2));
|
assertThat(result, hasSize(2));
|
||||||
Intent forwardResultIntent = result.get(0);
|
Intent forwardResultIntent = result.get(0);
|
||||||
|
@ -137,7 +137,7 @@ public class TestMultiPointToSinglePointIntentCompiler {
|
|||||||
MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
|
MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
|
||||||
assertThat(compiler, is(notNullValue()));
|
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, is(Matchers.notNullValue()));
|
||||||
assertThat(result, hasSize(1));
|
assertThat(result, hasSize(1));
|
||||||
Intent resultIntent = result.get(0);
|
Intent resultIntent = result.get(0);
|
||||||
@ -172,7 +172,7 @@ public class TestMultiPointToSinglePointIntentCompiler {
|
|||||||
MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
|
MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
|
||||||
assertThat(compiler, is(notNullValue()));
|
assertThat(compiler, is(notNullValue()));
|
||||||
|
|
||||||
List<Intent> result = compiler.compile(intent);
|
List<Intent> result = compiler.compile(intent, null, null);
|
||||||
assertThat(result, is(notNullValue()));
|
assertThat(result, is(notNullValue()));
|
||||||
assertThat(result, hasSize(1));
|
assertThat(result, hasSize(1));
|
||||||
Intent resultIntent = result.get(0);
|
Intent resultIntent = result.get(0);
|
||||||
@ -205,7 +205,7 @@ public class TestMultiPointToSinglePointIntentCompiler {
|
|||||||
MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
|
MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
|
||||||
assertThat(compiler, is(notNullValue()));
|
assertThat(compiler, is(notNullValue()));
|
||||||
|
|
||||||
List<Intent> result = compiler.compile(intent);
|
List<Intent> result = compiler.compile(intent, null, null);
|
||||||
assertThat(result, is(notNullValue()));
|
assertThat(result, is(notNullValue()));
|
||||||
assertThat(result, hasSize(1));
|
assertThat(result, hasSize(1));
|
||||||
Intent resultIntent = result.get(0);
|
Intent resultIntent = result.get(0);
|
||||||
|
@ -93,7 +93,7 @@ public class TestPointToPointIntentCompiler {
|
|||||||
PointToPointIntentCompiler compiler = makeCompiler(hops);
|
PointToPointIntentCompiler compiler = makeCompiler(hops);
|
||||||
assertThat(compiler, is(notNullValue()));
|
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, is(Matchers.notNullValue()));
|
||||||
assertThat(result, hasSize(1));
|
assertThat(result, hasSize(1));
|
||||||
Intent forwardResultIntent = result.get(0);
|
Intent forwardResultIntent = result.get(0);
|
||||||
@ -126,7 +126,7 @@ public class TestPointToPointIntentCompiler {
|
|||||||
PointToPointIntentCompiler compiler = makeCompiler(hops);
|
PointToPointIntentCompiler compiler = makeCompiler(hops);
|
||||||
assertThat(compiler, is(notNullValue()));
|
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, is(Matchers.notNullValue()));
|
||||||
assertThat(result, hasSize(1));
|
assertThat(result, hasSize(1));
|
||||||
Intent reverseResultIntent = result.get(0);
|
Intent reverseResultIntent = result.get(0);
|
||||||
@ -157,7 +157,7 @@ public class TestPointToPointIntentCompiler {
|
|||||||
String[] hops = {"1"};
|
String[] hops = {"1"};
|
||||||
PointToPointIntentCompiler sut = makeCompiler(hops);
|
PointToPointIntentCompiler sut = makeCompiler(hops);
|
||||||
|
|
||||||
List<Intent> compiled = sut.compile(intent);
|
List<Intent> compiled = sut.compile(intent, null, null);
|
||||||
|
|
||||||
assertThat(compiled, hasSize(1));
|
assertThat(compiled, hasSize(1));
|
||||||
assertThat(compiled.get(0), is(instanceOf(PathIntent.class)));
|
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.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
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;
|
import static org.slf4j.LoggerFactory.getLogger;
|
||||||
|
|
||||||
@Component(immediate = true)
|
@Component(immediate = true)
|
||||||
@ -45,8 +45,8 @@ public class SimpleIntentStore
|
|||||||
private final Logger log = getLogger(getClass());
|
private final Logger log = getLogger(getClass());
|
||||||
private final Map<IntentId, Intent> intents = new ConcurrentHashMap<>();
|
private final Map<IntentId, Intent> intents = new ConcurrentHashMap<>();
|
||||||
private final Map<IntentId, IntentState> states = new ConcurrentHashMap<>();
|
private final Map<IntentId, IntentState> states = new ConcurrentHashMap<>();
|
||||||
private final Map<IntentId, List<Intent>> installable =
|
private final Map<IntentId, List<Intent>> installable = new ConcurrentHashMap<>();
|
||||||
new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
@Activate
|
@Activate
|
||||||
public void activate() {
|
public void activate() {
|
||||||
@ -60,6 +60,9 @@ public class SimpleIntentStore
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IntentEvent createIntent(Intent intent) {
|
public IntentEvent createIntent(Intent intent) {
|
||||||
|
if (intents.containsKey(intent.id())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
intents.put(intent.id(), intent);
|
intents.put(intent.id(), intent);
|
||||||
return this.setState(intent, IntentState.SUBMITTED);
|
return this.setState(intent, IntentState.SUBMITTED);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user