mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-11-03 17:51:26 +01:00
Initial work for adding flow-objective backed intents.
Split installation work from IntentManager into IntentInstaller helper class. Change-Id: If926ce975d005abee4f22f2b05404de328d94203
This commit is contained in:
parent
b88b3f8bc6
commit
f6ec97b365
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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;
|
||||||
|
|
||||||
|
import com.google.common.base.MoreObjects;
|
||||||
|
import org.onosproject.core.ApplicationId;
|
||||||
|
import org.onosproject.net.NetworkResource;
|
||||||
|
import org.onosproject.net.flowobjective.Objective;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intent expressed as (and backed by) a collection of flow objectives through
|
||||||
|
* which the intent is to be accomplished.
|
||||||
|
*/
|
||||||
|
public class FlowObjectiveIntent extends Intent {
|
||||||
|
|
||||||
|
private final Collection<Objective> objectives;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for serialization.
|
||||||
|
*/
|
||||||
|
protected FlowObjectiveIntent() {
|
||||||
|
super();
|
||||||
|
this.objectives = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a flow objective intent with the specified objectives and
|
||||||
|
* resources.
|
||||||
|
*
|
||||||
|
* @param appId application id
|
||||||
|
* @param objectives backing flow objectives
|
||||||
|
* @param resources backing network resources
|
||||||
|
*/
|
||||||
|
public FlowObjectiveIntent(ApplicationId appId,
|
||||||
|
Collection<Objective> objectives,
|
||||||
|
Collection<NetworkResource> resources) {
|
||||||
|
this(appId, null, objectives, resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a flow objective intent with the specified objectives and
|
||||||
|
* resources.
|
||||||
|
*
|
||||||
|
* @param appId application id
|
||||||
|
* @param key intent key
|
||||||
|
* @param objectives backing flow objectives
|
||||||
|
* @param resources backing network resources
|
||||||
|
*/
|
||||||
|
public FlowObjectiveIntent(ApplicationId appId, Key key,
|
||||||
|
Collection<Objective> objectives,
|
||||||
|
Collection<NetworkResource> resources) {
|
||||||
|
super(appId, key, resources, DEFAULT_INTENT_PRIORITY);
|
||||||
|
this.objectives = objectives;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the collection of backing flow objectives.
|
||||||
|
*
|
||||||
|
* @return flow objectives
|
||||||
|
*/
|
||||||
|
Collection<Objective> objectives() {
|
||||||
|
return objectives;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInstallable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return MoreObjects.toStringHelper(this)
|
||||||
|
.add("id", id())
|
||||||
|
.add("key", key())
|
||||||
|
.add("appId", appId())
|
||||||
|
.add("resources", resources())
|
||||||
|
.add("objectives", objectives)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -25,6 +25,7 @@ public abstract class AbstractIntentTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
|
Intent.unbindIdGenerator(idGenerator);
|
||||||
Intent.bindIdGenerator(idGenerator);
|
Intent.bindIdGenerator(idGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.testing.EqualsTester;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.onosproject.core.ApplicationId;
|
||||||
|
import org.onosproject.core.DefaultApplicationId;
|
||||||
|
import org.onosproject.net.NetworkResource;
|
||||||
|
import org.onosproject.net.flow.DefaultTrafficSelector;
|
||||||
|
import org.onosproject.net.flow.DefaultTrafficTreatment;
|
||||||
|
import org.onosproject.net.flow.criteria.Criteria;
|
||||||
|
import org.onosproject.net.flowobjective.DefaultFilteringObjective;
|
||||||
|
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
|
||||||
|
import org.onosproject.net.flowobjective.ForwardingObjective;
|
||||||
|
import org.onosproject.net.flowobjective.Objective;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests of the flow objective intent.
|
||||||
|
*/
|
||||||
|
public class FlowObjectiveIntentTest extends IntentTest {
|
||||||
|
|
||||||
|
private static final ApplicationId APP_ID = new DefaultApplicationId(1, "foo");
|
||||||
|
private static final Key KEY = Key.of("bar", APP_ID);
|
||||||
|
|
||||||
|
private static final Objective FO1 = DefaultFilteringObjective.builder()
|
||||||
|
.fromApp(APP_ID).addCondition(Criteria.matchEthType(123))
|
||||||
|
.permit().add();
|
||||||
|
private static final Objective FO2 = DefaultForwardingObjective.builder()
|
||||||
|
.fromApp(APP_ID)
|
||||||
|
.withSelector(DefaultTrafficSelector.builder().matchEthType((short) 123).build())
|
||||||
|
.withTreatment(DefaultTrafficTreatment.emptyTreatment())
|
||||||
|
.withFlag(ForwardingObjective.Flag.VERSATILE).add();
|
||||||
|
private static final Collection<Objective> OBJECTIVES = ImmutableSet.of(FO1, FO2);
|
||||||
|
private static final Collection<NetworkResource> RESOURCES = ImmutableSet.of();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests basics of construction and getters.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void basics() {
|
||||||
|
FlowObjectiveIntent intent =
|
||||||
|
new FlowObjectiveIntent(APP_ID, KEY, OBJECTIVES, RESOURCES);
|
||||||
|
assertEquals("incorrect app id", APP_ID, intent.appId());
|
||||||
|
assertEquals("incorrect key", KEY, intent.key());
|
||||||
|
assertEquals("incorrect objectives", OBJECTIVES, intent.objectives());
|
||||||
|
assertEquals("incorrect resources", RESOURCES, intent.resources());
|
||||||
|
assertTrue("should be installable", intent.isInstallable());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests equality.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void equality() {
|
||||||
|
Intent a = createOne();
|
||||||
|
Intent b = createAnother();
|
||||||
|
new EqualsTester().addEqualityGroup(a).addEqualityGroup(b).testEquals();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that instance is immutable.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testImmutability() {
|
||||||
|
assertThatClassIsImmutable(HostToHostIntent.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Intent createOne() {
|
||||||
|
return new FlowObjectiveIntent(APP_ID, OBJECTIVES, RESOURCES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Intent createAnother() {
|
||||||
|
return new FlowObjectiveIntent(APP_ID, OBJECTIVES, RESOURCES);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 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.FlowRule;
|
||||||
|
import org.onosproject.net.flow.FlowRuleOperations;
|
||||||
|
import org.onosproject.net.flow.FlowRuleOperationsContext;
|
||||||
|
import org.onosproject.net.flow.FlowRuleService;
|
||||||
|
import org.onosproject.net.flowobjective.FlowObjectiveService;
|
||||||
|
import org.onosproject.net.intent.FlowRuleIntent;
|
||||||
|
import org.onosproject.net.intent.Intent;
|
||||||
|
import org.onosproject.net.intent.IntentData;
|
||||||
|
import org.onosproject.net.intent.IntentStore;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.onosproject.net.intent.IntentState.*;
|
||||||
|
import static org.slf4j.LoggerFactory.getLogger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auxiliary entity responsible for installing the intents into the environment.
|
||||||
|
*/
|
||||||
|
class IntentInstaller {
|
||||||
|
|
||||||
|
private static final Logger log = getLogger(IntentManager.class);
|
||||||
|
|
||||||
|
private IntentStore store;
|
||||||
|
private ObjectiveTrackerService trackerService;
|
||||||
|
private FlowRuleService flowRuleService;
|
||||||
|
private FlowObjectiveService flowObjectiveService;
|
||||||
|
|
||||||
|
private enum Direction {
|
||||||
|
ADD,
|
||||||
|
REMOVE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the installer with references to required services.
|
||||||
|
*
|
||||||
|
* @param intentStore intent store
|
||||||
|
* @param trackerService objective tracking service
|
||||||
|
* @param flowRuleService flow rule service
|
||||||
|
* @param flowObjectiveService flow objective service
|
||||||
|
*/
|
||||||
|
void init(IntentStore intentStore, ObjectiveTrackerService trackerService,
|
||||||
|
FlowRuleService flowRuleService, FlowObjectiveService flowObjectiveService) {
|
||||||
|
this.store = intentStore;
|
||||||
|
this.trackerService = trackerService;
|
||||||
|
this.flowRuleService = flowRuleService;
|
||||||
|
this.flowObjectiveService = flowObjectiveService;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyIntentData(Optional<IntentData> intentData,
|
||||||
|
FlowRuleOperations.Builder builder,
|
||||||
|
Direction direction) {
|
||||||
|
if (!intentData.isPresent()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IntentData data = intentData.get();
|
||||||
|
|
||||||
|
List<Intent> intentsToApply = data.installables();
|
||||||
|
if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
|
||||||
|
throw new IllegalStateException("installable intents must be FlowRuleIntent");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (direction == Direction.ADD) {
|
||||||
|
trackerService.addTrackedResources(data.key(), data.intent().resources());
|
||||||
|
intentsToApply.forEach(installable ->
|
||||||
|
trackerService.addTrackedResources(data.key(), installable.resources()));
|
||||||
|
} else {
|
||||||
|
trackerService.removeTrackedResources(data.key(), data.intent().resources());
|
||||||
|
intentsToApply.forEach(installable ->
|
||||||
|
trackerService.removeTrackedResources(data.intent().key(),
|
||||||
|
installable.resources()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
|
||||||
|
builder.newStage();
|
||||||
|
|
||||||
|
List<Collection<FlowRule>> stages = intentsToApply.stream()
|
||||||
|
.map(x -> (FlowRuleIntent) x)
|
||||||
|
.map(FlowRuleIntent::flowRules)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
for (Collection<FlowRule> rules : stages) {
|
||||||
|
if (direction == Direction.ADD) {
|
||||||
|
rules.forEach(builder::add);
|
||||||
|
} else {
|
||||||
|
rules.forEach(builder::remove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Refactor to accept both FlowObjectiveIntent and FlowRuleIntents
|
||||||
|
// Note: Intent Manager should have never become dependent on a specific
|
||||||
|
// intent type.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the specified intent updates to the environment by uninstalling
|
||||||
|
* and installing the intents and updating the store references appropriately.
|
||||||
|
*
|
||||||
|
* @param toUninstall optional intent to uninstall
|
||||||
|
* @param toInstall optional intent to install
|
||||||
|
*/
|
||||||
|
void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
|
||||||
|
// need to consider if FlowRuleIntent is only one as installable intent or not
|
||||||
|
|
||||||
|
FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
|
||||||
|
applyIntentData(toUninstall, builder, Direction.REMOVE);
|
||||||
|
applyIntentData(toInstall, builder, Direction.ADD);
|
||||||
|
|
||||||
|
FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(FlowRuleOperations ops) {
|
||||||
|
if (toInstall.isPresent()) {
|
||||||
|
IntentData installData = toInstall.get();
|
||||||
|
log.debug("Completed installing: {}", installData.key());
|
||||||
|
installData.setState(INSTALLED);
|
||||||
|
store.write(installData);
|
||||||
|
} else if (toUninstall.isPresent()) {
|
||||||
|
IntentData uninstallData = toUninstall.get();
|
||||||
|
log.debug("Completed withdrawing: {}", uninstallData.key());
|
||||||
|
switch (uninstallData.request()) {
|
||||||
|
case INSTALL_REQ:
|
||||||
|
uninstallData.setState(FAILED);
|
||||||
|
break;
|
||||||
|
case WITHDRAW_REQ:
|
||||||
|
default: //TODO "default" case should not happen
|
||||||
|
uninstallData.setState(WITHDRAWN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
store.write(uninstallData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(FlowRuleOperations ops) {
|
||||||
|
// if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
|
||||||
|
if (toInstall.isPresent()) {
|
||||||
|
IntentData installData = toInstall.get();
|
||||||
|
log.warn("Failed installation: {} {} on {}",
|
||||||
|
installData.key(), installData.intent(), ops);
|
||||||
|
installData.setState(CORRUPT);
|
||||||
|
installData.incrementErrorCount();
|
||||||
|
store.write(installData);
|
||||||
|
}
|
||||||
|
// if toUninstall was cause of error, then CORRUPT (another job will clean this up)
|
||||||
|
if (toUninstall.isPresent()) {
|
||||||
|
IntentData uninstallData = toUninstall.get();
|
||||||
|
log.warn("Failed withdrawal: {} {} on {}",
|
||||||
|
uninstallData.key(), uninstallData.intent(), ops);
|
||||||
|
uninstallData.setState(CORRUPT);
|
||||||
|
uninstallData.incrementErrorCount();
|
||||||
|
store.write(uninstallData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (log.isTraceEnabled()) {
|
||||||
|
log.trace("applying intent {} -> {} with {} rules: {}",
|
||||||
|
toUninstall.map(x -> x.key().toString()).orElse("<empty>"),
|
||||||
|
toInstall.map(x -> x.key().toString()).orElse("<empty>"),
|
||||||
|
operations.stages().stream().mapToLong(Set::size).sum(),
|
||||||
|
operations.stages());
|
||||||
|
}
|
||||||
|
|
||||||
|
flowRuleService.apply(operations);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -25,11 +25,8 @@ import org.onlab.util.Tools;
|
|||||||
import org.onosproject.core.CoreService;
|
import org.onosproject.core.CoreService;
|
||||||
import org.onosproject.core.IdGenerator;
|
import org.onosproject.core.IdGenerator;
|
||||||
import org.onosproject.event.AbstractListenerManager;
|
import org.onosproject.event.AbstractListenerManager;
|
||||||
import org.onosproject.net.flow.FlowRule;
|
|
||||||
import org.onosproject.net.flow.FlowRuleOperations;
|
|
||||||
import org.onosproject.net.flow.FlowRuleOperationsContext;
|
|
||||||
import org.onosproject.net.flow.FlowRuleService;
|
import org.onosproject.net.flow.FlowRuleService;
|
||||||
import org.onosproject.net.intent.FlowRuleIntent;
|
import org.onosproject.net.flowobjective.FlowObjectiveService;
|
||||||
import org.onosproject.net.intent.Intent;
|
import org.onosproject.net.intent.Intent;
|
||||||
import org.onosproject.net.intent.IntentBatchDelegate;
|
import org.onosproject.net.intent.IntentBatchDelegate;
|
||||||
import org.onosproject.net.intent.IntentCompiler;
|
import org.onosproject.net.intent.IntentCompiler;
|
||||||
@ -61,13 +58,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||||||
import static java.util.concurrent.Executors.newFixedThreadPool;
|
import static java.util.concurrent.Executors.newFixedThreadPool;
|
||||||
import static java.util.concurrent.Executors.newSingleThreadExecutor;
|
import static java.util.concurrent.Executors.newSingleThreadExecutor;
|
||||||
import static org.onlab.util.Tools.groupedThreads;
|
import static org.onlab.util.Tools.groupedThreads;
|
||||||
import static org.onosproject.net.intent.IntentState.CORRUPT;
|
import static org.onosproject.net.intent.IntentState.*;
|
||||||
import static org.onosproject.net.intent.IntentState.FAILED;
|
|
||||||
import static org.onosproject.net.intent.IntentState.INSTALLED;
|
|
||||||
import static org.onosproject.net.intent.IntentState.INSTALL_REQ;
|
|
||||||
import static org.onosproject.net.intent.IntentState.WITHDRAWING;
|
|
||||||
import static org.onosproject.net.intent.IntentState.WITHDRAWN;
|
|
||||||
import static org.onosproject.net.intent.IntentState.WITHDRAW_REQ;
|
|
||||||
import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
|
import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
|
||||||
import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
|
import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
|
||||||
import static org.onosproject.security.AppGuard.checkPermission;
|
import static org.onosproject.security.AppGuard.checkPermission;
|
||||||
@ -75,7 +66,6 @@ import static org.onosproject.security.AppPermission.Type.INTENT_READ;
|
|||||||
import static org.onosproject.security.AppPermission.Type.INTENT_WRITE;
|
import static org.onosproject.security.AppPermission.Type.INTENT_WRITE;
|
||||||
import static org.slf4j.LoggerFactory.getLogger;
|
import static org.slf4j.LoggerFactory.getLogger;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of intent service.
|
* An implementation of intent service.
|
||||||
*/
|
*/
|
||||||
@ -109,12 +99,16 @@ public class IntentManager
|
|||||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||||
protected FlowRuleService flowRuleService;
|
protected FlowRuleService flowRuleService;
|
||||||
|
|
||||||
|
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||||
|
protected FlowObjectiveService flowObjectiveService;
|
||||||
|
|
||||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||||
protected ResourceService resourceService;
|
protected ResourceService resourceService;
|
||||||
|
|
||||||
private ExecutorService batchExecutor;
|
private ExecutorService batchExecutor;
|
||||||
private ExecutorService workerExecutor;
|
private ExecutorService workerExecutor;
|
||||||
|
|
||||||
|
private final IntentInstaller intentInstaller = new IntentInstaller();
|
||||||
private final CompilerRegistry compilerRegistry = new CompilerRegistry();
|
private final CompilerRegistry compilerRegistry = new CompilerRegistry();
|
||||||
private final InternalIntentProcessor processor = new InternalIntentProcessor();
|
private final InternalIntentProcessor processor = new InternalIntentProcessor();
|
||||||
private final IntentStoreDelegate delegate = new InternalStoreDelegate();
|
private final IntentStoreDelegate delegate = new InternalStoreDelegate();
|
||||||
@ -126,6 +120,7 @@ public class IntentManager
|
|||||||
|
|
||||||
@Activate
|
@Activate
|
||||||
public void activate() {
|
public void activate() {
|
||||||
|
intentInstaller.init(store, trackerService, flowRuleService, flowObjectiveService);
|
||||||
store.setDelegate(delegate);
|
store.setDelegate(delegate);
|
||||||
trackerService.setDelegate(topoDelegate);
|
trackerService.setDelegate(topoDelegate);
|
||||||
eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
|
eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
|
||||||
@ -138,6 +133,7 @@ public class IntentManager
|
|||||||
|
|
||||||
@Deactivate
|
@Deactivate
|
||||||
public void deactivate() {
|
public void deactivate() {
|
||||||
|
intentInstaller.init(null, null, null, null);
|
||||||
store.unsetDelegate(delegate);
|
store.unsetDelegate(delegate);
|
||||||
trackerService.unsetDelegate(topoDelegate);
|
trackerService.unsetDelegate(topoDelegate);
|
||||||
eventDispatcher.removeSink(IntentEvent.class);
|
eventDispatcher.removeSink(IntentEvent.class);
|
||||||
@ -322,8 +318,8 @@ public class IntentManager
|
|||||||
|
|
||||||
// write multiple data to store in order
|
// write multiple data to store in order
|
||||||
store.batchWrite(Tools.allOf(futures).join().stream()
|
store.batchWrite(Tools.allOf(futures).join().stream()
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
}, batchExecutor).exceptionally(e -> {
|
}, batchExecutor).exceptionally(e -> {
|
||||||
log.error("Error submitting batches:", e);
|
log.error("Error submitting batches:", e);
|
||||||
// FIXME incomplete Intents should be cleaned up
|
// FIXME incomplete Intents should be cleaned up
|
||||||
@ -351,120 +347,8 @@ public class IntentManager
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
|
public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
|
||||||
IntentManager.this.apply(toUninstall, toInstall);
|
intentInstaller.apply(toUninstall, toInstall);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum Direction {
|
|
||||||
ADD,
|
|
||||||
REMOVE
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyIntentData(Optional<IntentData> intentData,
|
|
||||||
FlowRuleOperations.Builder builder,
|
|
||||||
Direction direction) {
|
|
||||||
if (!intentData.isPresent()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
IntentData data = intentData.get();
|
|
||||||
|
|
||||||
List<Intent> intentsToApply = data.installables();
|
|
||||||
if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
|
|
||||||
throw new IllegalStateException("installable intents must be FlowRuleIntent");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (direction == Direction.ADD) {
|
|
||||||
trackerService.addTrackedResources(data.key(), data.intent().resources());
|
|
||||||
intentsToApply.forEach(installable ->
|
|
||||||
trackerService.addTrackedResources(data.key(), installable.resources()));
|
|
||||||
} else {
|
|
||||||
trackerService.removeTrackedResources(data.key(), data.intent().resources());
|
|
||||||
intentsToApply.forEach(installable ->
|
|
||||||
trackerService.removeTrackedResources(data.intent().key(),
|
|
||||||
installable.resources()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
|
|
||||||
builder.newStage();
|
|
||||||
|
|
||||||
List<Collection<FlowRule>> stages = intentsToApply.stream()
|
|
||||||
.map(x -> (FlowRuleIntent) x)
|
|
||||||
.map(FlowRuleIntent::flowRules)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
for (Collection<FlowRule> rules : stages) {
|
|
||||||
if (direction == Direction.ADD) {
|
|
||||||
rules.forEach(builder::add);
|
|
||||||
} else {
|
|
||||||
rules.forEach(builder::remove);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
|
|
||||||
// need to consider if FlowRuleIntent is only one as installable intent or not
|
|
||||||
|
|
||||||
FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
|
|
||||||
applyIntentData(toUninstall, builder, Direction.REMOVE);
|
|
||||||
applyIntentData(toInstall, builder, Direction.ADD);
|
|
||||||
|
|
||||||
FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(FlowRuleOperations ops) {
|
|
||||||
if (toInstall.isPresent()) {
|
|
||||||
IntentData installData = toInstall.get();
|
|
||||||
log.debug("Completed installing: {}", installData.key());
|
|
||||||
installData.setState(INSTALLED);
|
|
||||||
store.write(installData);
|
|
||||||
} else if (toUninstall.isPresent()) {
|
|
||||||
IntentData uninstallData = toUninstall.get();
|
|
||||||
log.debug("Completed withdrawing: {}", uninstallData.key());
|
|
||||||
switch (uninstallData.request()) {
|
|
||||||
case INSTALL_REQ:
|
|
||||||
uninstallData.setState(FAILED);
|
|
||||||
break;
|
|
||||||
case WITHDRAW_REQ:
|
|
||||||
default: //TODO "default" case should not happen
|
|
||||||
uninstallData.setState(WITHDRAWN);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
store.write(uninstallData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(FlowRuleOperations ops) {
|
|
||||||
// if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
|
|
||||||
if (toInstall.isPresent()) {
|
|
||||||
IntentData installData = toInstall.get();
|
|
||||||
log.warn("Failed installation: {} {} on {}",
|
|
||||||
installData.key(), installData.intent(), ops);
|
|
||||||
installData.setState(CORRUPT);
|
|
||||||
installData.incrementErrorCount();
|
|
||||||
store.write(installData);
|
|
||||||
}
|
|
||||||
// if toUninstall was cause of error, then CORRUPT (another job will clean this up)
|
|
||||||
if (toUninstall.isPresent()) {
|
|
||||||
IntentData uninstallData = toUninstall.get();
|
|
||||||
log.warn("Failed withdrawal: {} {} on {}",
|
|
||||||
uninstallData.key(), uninstallData.intent(), ops);
|
|
||||||
uninstallData.setState(CORRUPT);
|
|
||||||
uninstallData.incrementErrorCount();
|
|
||||||
store.write(uninstallData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (log.isTraceEnabled()) {
|
|
||||||
log.trace("applying intent {} -> {} with {} rules: {}",
|
|
||||||
toUninstall.map(x -> x.key().toString()).orElse("<empty>"),
|
|
||||||
toInstall.map(x -> x.key().toString()).orElse("<empty>"),
|
|
||||||
operations.stages().stream().mapToLong(i -> i.size()).sum(),
|
|
||||||
operations.stages());
|
|
||||||
}
|
|
||||||
|
|
||||||
flowRuleService.apply(operations);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user