blob: 6802aba375845c628b5ccaccf778932ece286c05 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Sho SHIMIZU89925242016-01-13 14:20:34 -08002 * Copyright 2014-2016 Open Networking Laboratory
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net.intent.impl;
Brian O'Connor66630c82014-10-02 21:08:19 -070017
Brian O'Connor66630c82014-10-02 21:08:19 -070018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
23import org.apache.felix.scr.annotations.Service;
Sho SHIMIZUe0981722016-01-14 16:02:48 -080024import org.onlab.util.Tools;
Brian O'Connorabafb502014-12-02 22:26:20 -080025import org.onosproject.core.CoreService;
26import org.onosproject.core.IdGenerator;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080027import org.onosproject.event.AbstractListenerManager;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080028import org.onosproject.net.flow.FlowRule;
Brian O'Connor0e271dc2015-02-04 18:20:25 -080029import org.onosproject.net.flow.FlowRuleOperations;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080030import org.onosproject.net.flow.FlowRuleOperationsContext;
Brian O'Connorabafb502014-12-02 22:26:20 -080031import org.onosproject.net.flow.FlowRuleService;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080032import org.onosproject.net.intent.FlowRuleIntent;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.net.intent.Intent;
34import org.onosproject.net.intent.IntentBatchDelegate;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.intent.IntentCompiler;
Brian O'Connorcff03322015-02-03 15:28:59 -080036import org.onosproject.net.intent.IntentData;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.net.intent.IntentEvent;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.net.intent.IntentExtensionService;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.intent.IntentListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.net.intent.IntentService;
41import org.onosproject.net.intent.IntentState;
42import org.onosproject.net.intent.IntentStore;
Brian O'Connorabafb502014-12-02 22:26:20 -080043import org.onosproject.net.intent.IntentStoreDelegate;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080044import org.onosproject.net.intent.Key;
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -080045import org.onosproject.net.intent.impl.phase.FinalIntentProcessPhase;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080046import org.onosproject.net.intent.impl.phase.IntentProcessPhase;
Brian O'Connor66630c82014-10-02 21:08:19 -070047import org.slf4j.Logger;
48
Brian O'Connorf0c5a052015-04-27 00:34:53 -070049import java.util.Collection;
50import java.util.EnumSet;
51import java.util.List;
52import java.util.Map;
Sho SHIMIZUab541a52016-01-13 23:29:32 -080053import java.util.Objects;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070054import java.util.Optional;
Sho SHIMIZUad8ab272016-01-13 22:08:58 -080055import java.util.concurrent.CompletableFuture;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070056import java.util.concurrent.ExecutorService;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070057import java.util.stream.Collectors;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070058
Brian O'Connorfa81eae2014-10-30 13:20:05 -070059import static com.google.common.base.Preconditions.checkNotNull;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080060import static java.util.concurrent.Executors.newFixedThreadPool;
Brian O'Connordb15b042015-02-04 14:59:28 -080061import static java.util.concurrent.Executors.newSingleThreadExecutor;
Brian O'Connorbdc7f002015-02-18 20:49:41 -080062import static org.onlab.util.Tools.groupedThreads;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080063import static org.onosproject.net.intent.IntentState.CORRUPT;
64import static org.onosproject.net.intent.IntentState.FAILED;
65import static org.onosproject.net.intent.IntentState.INSTALLED;
66import static org.onosproject.net.intent.IntentState.INSTALL_REQ;
67import static org.onosproject.net.intent.IntentState.WITHDRAWING;
68import static org.onosproject.net.intent.IntentState.WITHDRAWN;
69import static org.onosproject.net.intent.IntentState.WITHDRAW_REQ;
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070070import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080071import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
Changhoon Yoon541ef712015-05-23 17:18:34 +090072import static org.onosproject.security.AppGuard.checkPermission;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080073import static org.onosproject.security.AppPermission.Type.INTENT_READ;
74import static org.onosproject.security.AppPermission.Type.INTENT_WRITE;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070075import static org.slf4j.LoggerFactory.getLogger;
Changhoon Yoonb856b812015-08-10 03:47:19 +090076
Brian O'Connor66630c82014-10-02 21:08:19 -070077
78/**
Brian O'Connorce2d8b52015-07-29 16:24:13 -070079 * An implementation of intent service.
Brian O'Connor66630c82014-10-02 21:08:19 -070080 */
81@Component(immediate = true)
82@Service
83public class IntentManager
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070084 extends AbstractListenerManager<IntentEvent, IntentListener>
Brian O'Connor66630c82014-10-02 21:08:19 -070085 implements IntentService, IntentExtensionService {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070086
Sho SHIMIZU8b5051d2014-11-05 11:24:13 -080087 private static final Logger log = getLogger(IntentManager.class);
Brian O'Connor66630c82014-10-02 21:08:19 -070088
89 public static final String INTENT_NULL = "Intent cannot be null";
Ray Milkeyf9af43c2015-02-09 16:45:48 -080090 public static final String INTENT_ID_NULL = "Intent key cannot be null";
Brian O'Connor66630c82014-10-02 21:08:19 -070091
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080092 private static final int NUM_THREADS = 12;
93
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080094 private static final EnumSet<IntentState> RECOMPILE
95 = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070096 private static final EnumSet<IntentState> WITHDRAW
97 = EnumSet.of(WITHDRAW_REQ, WITHDRAWING, WITHDRAWN);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080098
Brian O'Connor520c0522014-11-23 23:50:47 -080099 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected CoreService coreService;
Brian O'Connor66630c82014-10-02 21:08:19 -0700101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected IntentStore store;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -0700106 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -0700107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZU214ac322015-02-23 19:30:15 -0800109 protected FlowRuleService flowRuleService;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700110
Brian O'Connordb15b042015-02-04 14:59:28 -0800111 private ExecutorService batchExecutor;
112 private ExecutorService workerExecutor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800113
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800114 private final CompilerRegistry compilerRegistry = new CompilerRegistry();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800115 private final InternalIntentProcessor processor = new InternalIntentProcessor();
Brian O'Connor520c0522014-11-23 23:50:47 -0800116 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
117 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
118 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
119 private IdGenerator idGenerator;
120
Brian O'Connorb499b352015-02-03 16:46:15 -0800121 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800122
Brian O'Connor66630c82014-10-02 21:08:19 -0700123 @Activate
124 public void activate() {
125 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700126 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700127 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorbdc7f002015-02-18 20:49:41 -0800128 batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch"));
129 workerExecutor = newFixedThreadPool(NUM_THREADS, groupedThreads("onos/intent", "worker-%d"));
Brian O'Connor520c0522014-11-23 23:50:47 -0800130 idGenerator = coreService.getIdGenerator("intent-ids");
131 Intent.bindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700132 log.info("Started");
133 }
134
135 @Deactivate
136 public void deactivate() {
137 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700138 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700139 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connordb15b042015-02-04 14:59:28 -0800140 batchExecutor.shutdown();
Brian O'Connor3c58e962015-04-28 23:21:51 -0700141 workerExecutor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800142 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700143 log.info("Stopped");
144 }
145
146 @Override
147 public void submit(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900148 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700149 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800150 IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800151 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700152 }
153
154 @Override
155 public void withdraw(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900156 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700157 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800158 IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800159 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700160 }
161
Brian O'Connor66630c82014-10-02 21:08:19 -0700162 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700163 public void purge(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900164 checkPermission(INTENT_WRITE);
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700165 checkNotNull(intent, INTENT_NULL);
166 IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null);
167 store.addPending(data);
168 }
169
170 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800171 public Intent getIntent(Key key) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900172 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800173 return store.getIntent(key);
174 }
175
176 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700177 public Iterable<Intent> getIntents() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900178 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700179 return store.getIntents();
180 }
181
182 @Override
Thomas Vachuskac46af202015-06-03 16:43:27 -0700183 public Iterable<IntentData> getIntentData() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900184 checkPermission(INTENT_READ);
Thomas Vachuskac46af202015-06-03 16:43:27 -0700185 return store.getIntentData(false, 0);
186 }
187
188 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700189 public long getIntentCount() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900190 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700191 return store.getIntentCount();
192 }
193
194 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800195 public IntentState getIntentState(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900196 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800197 checkNotNull(intentKey, INTENT_ID_NULL);
198 return store.getIntentState(intentKey);
Brian O'Connor66630c82014-10-02 21:08:19 -0700199 }
200
201 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800202 public List<Intent> getInstallableIntents(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900203 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800204 checkNotNull(intentKey, INTENT_ID_NULL);
205 return store.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700206 }
207
208 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800209 public boolean isLocal(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900210 checkPermission(INTENT_READ);
Brian O'Connorbe28a872015-02-19 21:44:37 -0800211 return store.isMaster(intentKey);
212 }
213
214 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700215 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800216 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700217 }
218
219 @Override
220 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800221 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700222 }
223
224 @Override
225 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800226 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700227 }
228
229 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800230 public Iterable<Intent> getPending() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900231 checkPermission(INTENT_READ);
Changhoon Yoon541ef712015-05-23 17:18:34 +0900232
Jonathan Hart34f1e382015-02-24 16:52:23 -0800233 return store.getPending();
234 }
235
Brian O'Connor66630c82014-10-02 21:08:19 -0700236 // Store delegate to re-post events emitted from the store.
237 private class InternalStoreDelegate implements IntentStoreDelegate {
238 @Override
239 public void notify(IntentEvent event) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700240 post(event);
Brian O'Connor66630c82014-10-02 21:08:19 -0700241 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800242
243 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800244 public void process(IntentData data) {
245 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800246 }
Thomas Vachuskac46af202015-06-03 16:43:27 -0700247
248 @Override
249 public void onUpdate(IntentData intentData) {
250 trackerService.trackIntent(intentData);
251 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700252 }
253
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800254 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800255 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800256 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800257 for (Key key : intentKeys) {
258 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800259 if (intent == null) {
260 continue;
261 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800262 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800263 }
264
Jonathan Hart0cca3e82015-09-23 17:54:11 -0700265 if (compileAllFailed) {
266 // If required, compile all currently failed intents.
267 for (Intent intent : getIntents()) {
268 IntentState state = getIntentState(intent.key());
269 if (RECOMPILE.contains(state) || intentAllowsPartialFailure(intent)) {
270 if (WITHDRAW.contains(state)) {
271 withdraw(intent);
272 } else {
273 submit(intent);
274 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800275 }
276 }
277 }
278
Brian O'Connorb499b352015-02-03 16:46:15 -0800279 //FIXME
280// for (ApplicationId appId : batches.keySet()) {
281// if (batchService.isLocalLeader(appId)) {
282// execute(batches.get(appId).build());
283// }
284// }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800285 }
286
tom95329eb2014-10-06 08:40:06 -0700287 // Topology change delegate
288 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
289 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800290 public void triggerCompile(Iterable<Key> intentKeys,
tom85258ee2014-10-07 00:10:02 -0700291 boolean compileAllFailed) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800292 buildAndSubmitBatches(intentKeys, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700293 }
tom95329eb2014-10-06 08:40:06 -0700294 }
tom85258ee2014-10-07 00:10:02 -0700295
Sho SHIMIZU594fb2a2016-01-14 16:12:26 -0800296 private IntentProcessPhase createInitialPhase(IntentData data) {
297 IntentData current = store.getIntentData(data.key());
298 return newInitialPhase(processor, data, current);
299 }
300
301 private FinalIntentProcessPhase process(IntentProcessPhase initial) {
302 Optional<IntentProcessPhase> currentPhase = Optional.of(initial);
303 IntentProcessPhase previousPhase = initial;
304
305 while (currentPhase.isPresent()) {
306 previousPhase = currentPhase.get();
307 currentPhase = previousPhase.execute();
308 }
309 return (FinalIntentProcessPhase) previousPhase;
Sho SHIMIZU8d9d1362015-02-04 12:28:15 -0800310 }
311
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700312 private class InternalBatchDelegate implements IntentBatchDelegate {
313 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800314 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800315 log.debug("Execute {} operation(s).", operations.size());
316 log.trace("Execute operations: {}", operations);
Sho SHIMIZU94b03b12015-04-10 14:53:13 -0700317
318 // batchExecutor is single-threaded, so only one batch is in flight at a time
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800319 batchExecutor.execute(() -> {
320 try {
321 /*
322 1. wrap each intentdata in a runnable and submit
323 2. wait for completion of all the work
324 3. accumulate results and submit batch write of IntentData to store
325 (we can also try to update these individually)
326 */
Sho SHIMIZUe0981722016-01-14 16:02:48 -0800327 List<CompletableFuture<IntentData>> futures = operations.stream()
Sho SHIMIZUc95ec3e2016-01-14 16:19:54 -0800328 .map(x -> createInitialPhase(x))
329 .map(x -> CompletableFuture.supplyAsync(() -> process(x), workerExecutor))
Sho SHIMIZUe0981722016-01-14 16:02:48 -0800330 .map(x -> x.thenApply(FinalIntentProcessPhase::data))
Sho SHIMIZUd7558932016-01-13 23:47:46 -0800331 .map(x -> x.exceptionally(e -> {
332 //FIXME
333 log.warn("Future failed: {}", e);
334 return null;
335 }))
Sho SHIMIZUe0981722016-01-14 16:02:48 -0800336 .collect(Collectors.toList());
337 store.batchWrite(Tools.allOf(futures).join().stream()
Sho SHIMIZUd7558932016-01-13 23:47:46 -0800338 .filter(Objects::nonNull)
Sho SHIMIZUd7558932016-01-13 23:47:46 -0800339 .collect(Collectors.toList()));
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800340 } catch (Exception e) {
341 log.error("Error submitting batches:", e);
342 // FIXME incomplete Intents should be cleaned up
343 // (transition to FAILED, etc.)
344
345 // the batch has failed
346 // TODO: maybe we should do more?
347 log.error("Walk the plank, matey...");
348 //FIXME
349// batchService.removeIntentOperations(data);
350 }
351 accumulator.ready();
352 });
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700353 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700354 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800355
356 private class InternalIntentProcessor implements IntentProcessor {
357 @Override
358 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
359 return compilerRegistry.compile(intent, previousInstallables);
360 }
361
362 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700363 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700364 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800365 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700366 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800367
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700368 private enum Direction {
369 ADD,
370 REMOVE
371 }
372
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700373 private void applyIntentData(Optional<IntentData> intentData,
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700374 FlowRuleOperations.Builder builder,
375 Direction direction) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700376 if (!intentData.isPresent()) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700377 return;
378 }
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700379 IntentData data = intentData.get();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700380
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700381 List<Intent> intentsToApply = data.installables();
382 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
383 throw new IllegalStateException("installable intents must be FlowRuleIntent");
384 }
385
386 if (direction == Direction.ADD) {
387 trackerService.addTrackedResources(data.key(), data.intent().resources());
388 intentsToApply.forEach(installable ->
389 trackerService.addTrackedResources(data.key(), installable.resources()));
390 } else {
391 trackerService.removeTrackedResources(data.key(), data.intent().resources());
392 intentsToApply.forEach(installable ->
393 trackerService.removeTrackedResources(data.intent().key(),
394 installable.resources()));
395 }
396
397 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
398 builder.newStage();
399
400 List<Collection<FlowRule>> stages = intentsToApply.stream()
401 .map(x -> (FlowRuleIntent) x)
402 .map(FlowRuleIntent::flowRules)
403 .collect(Collectors.toList());
404
405 for (Collection<FlowRule> rules : stages) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700406 if (direction == Direction.ADD) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700407 rules.forEach(builder::add);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700408 } else {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700409 rules.forEach(builder::remove);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700410 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800411 }
412
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800413 }
414
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700415 private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800416 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800417
418 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700419 applyIntentData(toUninstall, builder, Direction.REMOVE);
420 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800421
422 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
423 @Override
424 public void onSuccess(FlowRuleOperations ops) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700425 if (toInstall.isPresent()) {
426 IntentData installData = toInstall.get();
427 log.debug("Completed installing: {}", installData.key());
428 installData.setState(INSTALLED);
429 store.write(installData);
430 } else if (toUninstall.isPresent()) {
431 IntentData uninstallData = toUninstall.get();
432 log.debug("Completed withdrawing: {}", uninstallData.key());
433 switch (uninstallData.request()) {
434 case INSTALL_REQ:
435 uninstallData.setState(FAILED);
436 break;
437 case WITHDRAW_REQ:
438 default: //TODO "default" case should not happen
439 uninstallData.setState(WITHDRAWN);
440 break;
441 }
442 store.write(uninstallData);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700443 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800444 }
445
446 @Override
447 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700448 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700449 if (toInstall.isPresent()) {
450 IntentData installData = toInstall.get();
451 log.warn("Failed installation: {} {} on {}",
452 installData.key(), installData.intent(), ops);
453 installData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700454 installData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700455 store.write(installData);
456 }
Sho SHIMIZUd4936252015-04-10 15:03:57 -0700457 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700458 if (toUninstall.isPresent()) {
459 IntentData uninstallData = toUninstall.get();
460 log.warn("Failed withdrawal: {} {} on {}",
461 uninstallData.key(), uninstallData.intent(), ops);
462 uninstallData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700463 uninstallData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700464 store.write(uninstallData);
465 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800466 }
467 });
468
Brian O'Connora7674262015-06-04 13:55:18 -0700469 if (log.isTraceEnabled()) {
470 log.trace("applying intent {} -> {} with {} rules: {}",
Sho SHIMIZU98c0a392016-01-14 18:40:53 -0800471 toUninstall.map(x -> x.key().toString()).orElse("<empty>"),
472 toInstall.map(x -> x.key().toString()).orElse("<empty>"),
473 operations.stages().stream().mapToLong(i -> i.size()).sum(),
474 operations.stages());
Brian O'Connora7674262015-06-04 13:55:18 -0700475 }
476
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800477 flowRuleService.apply(operations);
478 }
479
Brian O'Connor66630c82014-10-02 21:08:19 -0700480}