Brian O'Connor

Intent F/W improvements

 - aggregate installables into FlowRuleOperations
 - added some impl. to SimpleIntentStore
 - created Coordinating State

Change-Id: I5b26ec1fdb7aaff9d5da4f21b2d5a249568ac5ac
......@@ -15,16 +15,14 @@
*/
package org.onosproject.net.intent;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleBatchEntry;
import org.onosproject.net.flow.FlowRuleBatchOperation;
import org.onosproject.net.flow.FlowRuleOperations;
import java.util.List;
/**
* Abstraction of entity capable of installing intents to the environment.
*/
//TODO consider refactoring this API
public interface IntentInstaller<T extends Intent> {
/**
* Installs the specified intent to the environment.
......@@ -33,32 +31,7 @@ public interface IntentInstaller<T extends Intent> {
* @return flow rule operations to complete install
* @throws IntentException if issues are encountered while installing the intent
*/
@Deprecated
List<FlowRuleBatchOperation> install(T intent);
// FIXME
default FlowRuleOperations.Builder install2(T intent) {
FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
for (FlowRuleBatchOperation batch : install(intent)) {
for (FlowRuleBatchEntry entry : batch.getOperations()) {
FlowRule rule = entry.target();
switch (entry.operator()) {
case ADD:
builder.add(rule);
break;
case REMOVE:
builder.remove(rule);
break;
case MODIFY:
builder.modify(rule);
break;
default:
break;
}
}
builder.newStage();
}
return builder;
}
/**
* Uninstalls the specified intent from the environment.
......@@ -67,32 +40,7 @@ public interface IntentInstaller<T extends Intent> {
* @return flow rule operations to complete uninstall
* @throws IntentException if issues are encountered while uninstalling the intent
*/
@Deprecated
List<FlowRuleBatchOperation> uninstall(T intent);
// FIXME
default FlowRuleOperations.Builder uninstall2(T intent) {
FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
for (FlowRuleBatchOperation batch : uninstall(intent)) {
for (FlowRuleBatchEntry entry : batch.getOperations()) {
FlowRule rule = entry.target();
switch (entry.operator()) {
case ADD:
builder.add(rule);
break;
case REMOVE:
builder.remove(rule);
break;
case MODIFY:
builder.modify(rule);
break;
default:
break;
}
}
builder.newStage();
}
return builder;
}
/**
* Replaces the specified intent with a new one in the environment.
......@@ -104,29 +52,5 @@ public interface IntentInstaller<T extends Intent> {
*/
@Deprecated
List<FlowRuleBatchOperation> replace(T oldIntent, T newIntent);
// FIXME
default FlowRuleOperations.Builder replace2(T oldIntent, T newIntent) {
FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
for (FlowRuleBatchOperation batch : replace(oldIntent, newIntent)) {
for (FlowRuleBatchEntry entry : batch.getOperations()) {
FlowRule rule = entry.target();
switch (entry.operator()) {
case ADD:
builder.add(rule);
break;
case REMOVE:
builder.remove(rule);
break;
case MODIFY:
builder.modify(rule);
break;
default:
break;
}
}
builder.newStage();
}
return builder;
}
}
......
......@@ -46,7 +46,7 @@ class Compiling implements IntentUpdate {
try {
List<Intent> installables = (current != null) ? current.installables() : null;
pending.setInstallables(intentManager.compileIntent(pending.intent(), installables));
return Optional.of(new Installing(intentManager, pending, current));
return Optional.of(new Coordinating(intentManager, pending, current));
} catch (PathNotFoundException e) {
log.debug("Path not found for intent {}", pending.intent());
// TODO: revisit to implement failure handling
......
/*
* Copyright 2015 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.onosproject.net.intent.impl;
import org.onosproject.net.flow.FlowRuleOperations;
import org.onosproject.net.intent.IntentData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkNotNull;
// TODO: better naming because install() method actually generate FlowRuleBatchOperations
class Coordinating implements IntentUpdate {
private static final Logger log = LoggerFactory.getLogger(Coordinating.class);
private final IntentManager intentManager;
private final IntentData pending;
private final IntentData current;
// TODO: define an interface and use it, instead of IntentManager
Coordinating(IntentManager intentManager, IntentData pending, IntentData current) {
this.intentManager = checkNotNull(intentManager);
this.pending = checkNotNull(pending);
this.current = current;
}
@Override
public Optional<IntentUpdate> execute() {
try {
FlowRuleOperations flowRules = intentManager.coordinate(pending);
return Optional.of(new Installing(intentManager, pending, flowRules));
} catch (FlowRuleBatchOperationConversionException e) {
log.warn("Unable to install intent {} due to:", pending.intent().id(), e.getCause());
return Optional.of(new InstallingFailed(pending)); //FIXME
}
}
}
......@@ -31,22 +31,19 @@ class Installing implements IntentUpdate {
private final IntentManager intentManager;
private final IntentData pending;
private final IntentData current;
private final FlowRuleOperations flowRules;
// TODO: define an interface and use it, instead of IntentManager
Installing(IntentManager intentManager, IntentData pending, IntentData current) {
Installing(IntentManager intentManager, IntentData pending, FlowRuleOperations flowRules) {
this.intentManager = checkNotNull(intentManager);
this.pending = checkNotNull(pending);
this.current = current;
this.flowRules = flowRules;
}
@Override
public Optional<IntentUpdate> execute() {
try {
FlowRuleOperations flowRules = intentManager.coordinate(pending.installables());
// TODO: call FlowRuleService API to push FlowRules and track resources,
// which the submitted intent will use.
intentManager.flowRuleService.apply(flowRules);
intentManager.flowRuleService.apply(flowRules); // FIXME we need to provide a context
return Optional.of(new Installed(pending));
} catch (FlowRuleBatchOperationConversionException e) {
log.warn("Unable to install intent {} due to:", pending.intent().id(), e.getCause());
......
......@@ -28,8 +28,13 @@ import org.onosproject.core.CoreService;
import org.onosproject.core.IdGenerator;
import org.onosproject.event.AbstractListenerRegistry;
import org.onosproject.event.EventDeliveryService;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleBatchEntry;
import org.onosproject.net.flow.FlowRuleBatchOperation;
import org.onosproject.net.flow.FlowRuleEvent;
import org.onosproject.net.flow.FlowRuleListener;
import org.onosproject.net.flow.FlowRuleOperations;
import org.onosproject.net.flow.FlowRuleOperationsContext;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentBatchDelegate;
......@@ -50,6 +55,7 @@ import org.slf4j.Logger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
......@@ -281,19 +287,74 @@ public class IntentManager
//TODO javadoc
//FIXME
FlowRuleOperations coordinate(List<Intent> installables) {
//List<FlowRuleBatchOperation> batches = new ArrayList<>(installables.size());
FlowRuleOperations coordinate(IntentData pending) {
List<Intent> installables = pending.installables();
List<List<FlowRuleBatchOperation>> plans = new ArrayList<>(installables.size());
for (Intent installable : installables) {
try {
registerSubclassInstallerIfNeeded(installable);
//FIXME need to migrate installers to FlowRuleOperations
// FIXME need to aggregate the FlowRuleOperations across installables
getInstaller(installable).install2(installable).build(null/*FIXME*/);
plans.add(getInstaller(installable).install(installable));
} catch (Exception e) { // TODO this should be IntentException
throw new FlowRuleBatchOperationConversionException(null/*FIXME*/, e);
}
}
return null;
return merge(plans).build(new FlowRuleOperationsContext() { // FIXME move this out
@Override
public void onSuccess(FlowRuleOperations ops) {
log.info("Completed installing: {}", pending.key());
pending.setState(INSTALLED);
store.write(pending);
}
@Override
public void onError(FlowRuleOperations ops) {
//FIXME store.write(pending.setState(BROKEN));
}
});
}
// FIXME... needs tests... or maybe it's just perfect
private FlowRuleOperations.Builder merge(List<List<FlowRuleBatchOperation>> plans) {
FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
// Build a batch one stage at a time
for (int stageNumber = 0;; stageNumber++) {
// Get the sub-stage from each plan (List<FlowRuleBatchOperation>)
for (Iterator<List<FlowRuleBatchOperation>> itr = plans.iterator(); itr.hasNext();) {
List<FlowRuleBatchOperation> plan = itr.next();
if (plan.size() <= stageNumber) {
// we have consumed all stages from this plan, so remove it
itr.remove();
continue;
}
// write operations from this sub-stage into the builder
FlowRuleBatchOperation stage = plan.get(stageNumber);
for (FlowRuleBatchEntry entry : stage.getOperations()) {
FlowRule rule = entry.target();
switch (entry.operator()) {
case ADD:
builder.add(rule);
break;
case REMOVE:
builder.remove(rule);
break;
case MODIFY:
builder.modify(rule);
break;
default:
break;
}
}
}
// we are done with the stage, start the next one...
if (plans.isEmpty()) {
break; // we don't need to start a new stage, we are done.
}
builder.newStage();
}
return builder;
}
/**
......@@ -311,7 +372,7 @@ public class IntentManager
installable.resources());
try {
// FIXME need to aggregate the FlowRuleOperations across installables
getInstaller(installable).uninstall2(installable).build(null/*FIXME*/);
getInstaller(installable).uninstall(installable); //.build(null/*FIXME*/);
} catch (IntentException e) {
log.warn("Unable to uninstall intent {} due to:", intent.id(), e);
// TODO: this should never happen. but what if it does?
......
......@@ -25,6 +25,8 @@ import org.onosproject.net.intent.BatchWrite.Operation;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentData;
import org.onosproject.net.intent.IntentEvent;
import org.onosproject.net.intent.IntentId;
import org.onosproject.net.intent.IntentState;
import org.onosproject.net.intent.IntentStore;
import org.onosproject.net.intent.IntentStoreDelegate;
import org.onosproject.net.intent.Key;
......@@ -33,6 +35,7 @@ import org.slf4j.Logger;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
......@@ -73,6 +76,36 @@ public class SimpleIntentStore
}
@Override
public Intent getIntent(IntentId intentId) {
for (IntentData data : current.values()) {
if (Objects.equals(data.intent().id(), intentId)) {
return data.intent();
}
}
return null;
}
@Override
public IntentState getIntentState(IntentId intentId) {
for (IntentData data : current.values()) {
if (Objects.equals(data.intent().id(), intentId)) {
return data.state();
}
}
return null;
}
@Override
public List<Intent> getInstallableIntents(IntentId intentId) {
for (IntentData data : current.values()) {
if (Objects.equals(data.intent().id(), intentId)) {
return data.installables();
}
}
return null;
}
@Override
public IntentData getIntentData(Key key) {
return current.get(key);
}
......@@ -164,6 +197,12 @@ public class SimpleIntentStore
}
}
@Override
public Intent getIntent(Key key) {
IntentData data = current.get(key);
return (data != null) ? data.intent() : null;
}
@Override
public void addPending(IntentData data) {
......