blob: 324a561e17904481452d01e57012010bd0aba459 [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'Connorf0c5a052015-04-27 00:34:53 -070018import com.google.common.collect.ImmutableList;
Brian O'Connor66630c82014-10-02 21:08:19 -070019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070025import org.onosproject.event.AbstractListenerManager;
Brian O'Connorabafb502014-12-02 22:26:20 -080026import org.onosproject.core.CoreService;
27import org.onosproject.core.IdGenerator;
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;
53import java.util.Optional;
Sho SHIMIZUad8ab272016-01-13 22:08:58 -080054import java.util.concurrent.CompletableFuture;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070055import java.util.concurrent.ExecutionException;
56import 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;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070063import static org.onosproject.net.intent.IntentState.*;
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070064import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080065import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
Changhoon Yoon541ef712015-05-23 17:18:34 +090066import static org.onosproject.security.AppGuard.checkPermission;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070067import static org.slf4j.LoggerFactory.getLogger;
Changhoon Yoonb856b812015-08-10 03:47:19 +090068import static org.onosproject.security.AppPermission.Type.*;
69
Brian O'Connor66630c82014-10-02 21:08:19 -070070
71/**
Brian O'Connorce2d8b52015-07-29 16:24:13 -070072 * An implementation of intent service.
Brian O'Connor66630c82014-10-02 21:08:19 -070073 */
74@Component(immediate = true)
75@Service
76public class IntentManager
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070077 extends AbstractListenerManager<IntentEvent, IntentListener>
Brian O'Connor66630c82014-10-02 21:08:19 -070078 implements IntentService, IntentExtensionService {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070079
Sho SHIMIZU8b5051d2014-11-05 11:24:13 -080080 private static final Logger log = getLogger(IntentManager.class);
Brian O'Connor66630c82014-10-02 21:08:19 -070081
82 public static final String INTENT_NULL = "Intent cannot be null";
Ray Milkeyf9af43c2015-02-09 16:45:48 -080083 public static final String INTENT_ID_NULL = "Intent key cannot be null";
Brian O'Connor66630c82014-10-02 21:08:19 -070084
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080085 private static final int NUM_THREADS = 12;
86
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080087 private static final EnumSet<IntentState> RECOMPILE
88 = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070089 private static final EnumSet<IntentState> WITHDRAW
90 = EnumSet.of(WITHDRAW_REQ, WITHDRAWING, WITHDRAWN);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080091
Brian O'Connor520c0522014-11-23 23:50:47 -080092 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected CoreService coreService;
Brian O'Connor66630c82014-10-02 21:08:19 -070094
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected IntentStore store;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -070099 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -0700100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZU214ac322015-02-23 19:30:15 -0800102 protected FlowRuleService flowRuleService;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700103
Brian O'Connordb15b042015-02-04 14:59:28 -0800104 private ExecutorService batchExecutor;
105 private ExecutorService workerExecutor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800106
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800107 private final CompilerRegistry compilerRegistry = new CompilerRegistry();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800108 private final InternalIntentProcessor processor = new InternalIntentProcessor();
Brian O'Connor520c0522014-11-23 23:50:47 -0800109 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
110 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
111 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
112 private IdGenerator idGenerator;
113
Brian O'Connorb499b352015-02-03 16:46:15 -0800114 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800115
Brian O'Connor66630c82014-10-02 21:08:19 -0700116 @Activate
117 public void activate() {
118 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700119 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700120 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorbdc7f002015-02-18 20:49:41 -0800121 batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch"));
122 workerExecutor = newFixedThreadPool(NUM_THREADS, groupedThreads("onos/intent", "worker-%d"));
Brian O'Connor520c0522014-11-23 23:50:47 -0800123 idGenerator = coreService.getIdGenerator("intent-ids");
124 Intent.bindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700125 log.info("Started");
126 }
127
128 @Deactivate
129 public void deactivate() {
130 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700131 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700132 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connordb15b042015-02-04 14:59:28 -0800133 batchExecutor.shutdown();
Brian O'Connor3c58e962015-04-28 23:21:51 -0700134 workerExecutor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800135 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700136 log.info("Stopped");
137 }
138
139 @Override
140 public void submit(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900141 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700142 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800143 IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800144 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700145 }
146
147 @Override
148 public void withdraw(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900149 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700150 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800151 IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800152 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700153 }
154
Brian O'Connor66630c82014-10-02 21:08:19 -0700155 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700156 public void purge(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900157 checkPermission(INTENT_WRITE);
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700158 checkNotNull(intent, INTENT_NULL);
159 IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null);
160 store.addPending(data);
161 }
162
163 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800164 public Intent getIntent(Key key) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900165 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800166 return store.getIntent(key);
167 }
168
169 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700170 public Iterable<Intent> getIntents() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900171 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700172 return store.getIntents();
173 }
174
175 @Override
Thomas Vachuskac46af202015-06-03 16:43:27 -0700176 public Iterable<IntentData> getIntentData() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900177 checkPermission(INTENT_READ);
Thomas Vachuskac46af202015-06-03 16:43:27 -0700178 return store.getIntentData(false, 0);
179 }
180
181 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700182 public long getIntentCount() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900183 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700184 return store.getIntentCount();
185 }
186
187 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800188 public IntentState getIntentState(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900189 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800190 checkNotNull(intentKey, INTENT_ID_NULL);
191 return store.getIntentState(intentKey);
Brian O'Connor66630c82014-10-02 21:08:19 -0700192 }
193
194 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800195 public List<Intent> getInstallableIntents(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.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700199 }
200
201 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800202 public boolean isLocal(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900203 checkPermission(INTENT_READ);
Brian O'Connorbe28a872015-02-19 21:44:37 -0800204 return store.isMaster(intentKey);
205 }
206
207 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700208 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800209 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700210 }
211
212 @Override
213 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800214 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700215 }
216
217 @Override
218 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800219 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700220 }
221
222 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800223 public Iterable<Intent> getPending() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900224 checkPermission(INTENT_READ);
Changhoon Yoon541ef712015-05-23 17:18:34 +0900225
Jonathan Hart34f1e382015-02-24 16:52:23 -0800226 return store.getPending();
227 }
228
Brian O'Connor66630c82014-10-02 21:08:19 -0700229 // Store delegate to re-post events emitted from the store.
230 private class InternalStoreDelegate implements IntentStoreDelegate {
231 @Override
232 public void notify(IntentEvent event) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700233 post(event);
Brian O'Connor66630c82014-10-02 21:08:19 -0700234 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800235
236 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800237 public void process(IntentData data) {
238 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800239 }
Thomas Vachuskac46af202015-06-03 16:43:27 -0700240
241 @Override
242 public void onUpdate(IntentData intentData) {
243 trackerService.trackIntent(intentData);
244 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700245 }
246
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800247 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800248 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800249 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800250 for (Key key : intentKeys) {
251 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800252 if (intent == null) {
253 continue;
254 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800255 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800256 }
257
Jonathan Hart0cca3e82015-09-23 17:54:11 -0700258 if (compileAllFailed) {
259 // If required, compile all currently failed intents.
260 for (Intent intent : getIntents()) {
261 IntentState state = getIntentState(intent.key());
262 if (RECOMPILE.contains(state) || intentAllowsPartialFailure(intent)) {
263 if (WITHDRAW.contains(state)) {
264 withdraw(intent);
265 } else {
266 submit(intent);
267 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800268 }
269 }
270 }
271
Brian O'Connorb499b352015-02-03 16:46:15 -0800272 //FIXME
273// for (ApplicationId appId : batches.keySet()) {
274// if (batchService.isLocalLeader(appId)) {
275// execute(batches.get(appId).build());
276// }
277// }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800278 }
279
tom95329eb2014-10-06 08:40:06 -0700280 // Topology change delegate
281 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
282 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800283 public void triggerCompile(Iterable<Key> intentKeys,
tom85258ee2014-10-07 00:10:02 -0700284 boolean compileAllFailed) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800285 buildAndSubmitBatches(intentKeys, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700286 }
tom95329eb2014-10-06 08:40:06 -0700287 }
tom85258ee2014-10-07 00:10:02 -0700288
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800289 private CompletableFuture<FinalIntentProcessPhase> submitIntentData(IntentData data) {
Sho SHIMIZU0cb6fe62015-02-23 16:39:57 -0800290 IntentData current = store.getIntentData(data.key());
Sho SHIMIZUce49b602015-02-23 19:15:49 -0800291 IntentProcessPhase initial = newInitialPhase(processor, data, current);
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800292 return CompletableFuture.supplyAsync(() -> {
Sho SHIMIZU89925242016-01-13 14:20:34 -0800293 Optional<IntentProcessPhase> currentPhase = Optional.of(initial);
294 IntentProcessPhase previousPhase = initial;
295
296 while (currentPhase.isPresent()) {
297 previousPhase = currentPhase.get();
298 currentPhase = previousPhase.execute();
299 }
300 return (FinalIntentProcessPhase) previousPhase;
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800301 }, workerExecutor);
Sho SHIMIZU8d9d1362015-02-04 12:28:15 -0800302 }
303
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700304 private class InternalBatchDelegate implements IntentBatchDelegate {
305 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800306 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800307 log.debug("Execute {} operation(s).", operations.size());
308 log.trace("Execute operations: {}", operations);
Sho SHIMIZU94b03b12015-04-10 14:53:13 -0700309
310 // batchExecutor is single-threaded, so only one batch is in flight at a time
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800311 batchExecutor.execute(() -> {
312 try {
313 /*
314 1. wrap each intentdata in a runnable and submit
315 2. wait for completion of all the work
316 3. accumulate results and submit batch write of IntentData to store
317 (we can also try to update these individually)
318 */
319 submitUpdates(waitForFutures(createIntentUpdates(operations)));
320 } catch (Exception e) {
321 log.error("Error submitting batches:", e);
322 // FIXME incomplete Intents should be cleaned up
323 // (transition to FAILED, etc.)
324
325 // the batch has failed
326 // TODO: maybe we should do more?
327 log.error("Walk the plank, matey...");
328 //FIXME
329// batchService.removeIntentOperations(data);
330 }
331 accumulator.ready();
332 });
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700333 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700334 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800335
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800336 private List<CompletableFuture<FinalIntentProcessPhase>> createIntentUpdates(Collection<IntentData> data) {
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800337 return data.stream()
338 .map(IntentManager.this::submitIntentData)
339 .collect(Collectors.toList());
340 }
341
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800342 private List<FinalIntentProcessPhase> waitForFutures(List<CompletableFuture<FinalIntentProcessPhase>> futures) {
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800343 ImmutableList.Builder<FinalIntentProcessPhase> updateBuilder = ImmutableList.builder();
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800344 for (CompletableFuture<FinalIntentProcessPhase> future : futures) {
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800345 try {
346 updateBuilder.add(future.get());
347 } catch (InterruptedException | ExecutionException e) {
348 //FIXME
349 log.warn("Future failed: {}", e);
350 }
351 }
352 return updateBuilder.build();
353 }
354
355 private void submitUpdates(List<FinalIntentProcessPhase> updates) {
356 store.batchWrite(updates.stream()
357 .map(FinalIntentProcessPhase::data)
358 .collect(Collectors.toList()));
359 }
360
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800361 private class InternalIntentProcessor implements IntentProcessor {
362 @Override
363 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
364 return compilerRegistry.compile(intent, previousInstallables);
365 }
366
367 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700368 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700369 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800370 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700371 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800372
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700373 private enum Direction {
374 ADD,
375 REMOVE
376 }
377
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700378 private void applyIntentData(Optional<IntentData> intentData,
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700379 FlowRuleOperations.Builder builder,
380 Direction direction) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700381 if (!intentData.isPresent()) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700382 return;
383 }
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700384 IntentData data = intentData.get();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700385
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700386 List<Intent> intentsToApply = data.installables();
387 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
388 throw new IllegalStateException("installable intents must be FlowRuleIntent");
389 }
390
391 if (direction == Direction.ADD) {
392 trackerService.addTrackedResources(data.key(), data.intent().resources());
393 intentsToApply.forEach(installable ->
394 trackerService.addTrackedResources(data.key(), installable.resources()));
395 } else {
396 trackerService.removeTrackedResources(data.key(), data.intent().resources());
397 intentsToApply.forEach(installable ->
398 trackerService.removeTrackedResources(data.intent().key(),
399 installable.resources()));
400 }
401
402 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
403 builder.newStage();
404
405 List<Collection<FlowRule>> stages = intentsToApply.stream()
406 .map(x -> (FlowRuleIntent) x)
407 .map(FlowRuleIntent::flowRules)
408 .collect(Collectors.toList());
409
410 for (Collection<FlowRule> rules : stages) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700411 if (direction == Direction.ADD) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700412 rules.forEach(builder::add);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700413 } else {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700414 rules.forEach(builder::remove);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700415 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800416 }
417
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800418 }
419
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700420 private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800421 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800422
423 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700424 applyIntentData(toUninstall, builder, Direction.REMOVE);
425 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800426
427 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
428 @Override
429 public void onSuccess(FlowRuleOperations ops) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700430 if (toInstall.isPresent()) {
431 IntentData installData = toInstall.get();
432 log.debug("Completed installing: {}", installData.key());
433 installData.setState(INSTALLED);
434 store.write(installData);
435 } else if (toUninstall.isPresent()) {
436 IntentData uninstallData = toUninstall.get();
437 log.debug("Completed withdrawing: {}", uninstallData.key());
438 switch (uninstallData.request()) {
439 case INSTALL_REQ:
440 uninstallData.setState(FAILED);
441 break;
442 case WITHDRAW_REQ:
443 default: //TODO "default" case should not happen
444 uninstallData.setState(WITHDRAWN);
445 break;
446 }
447 store.write(uninstallData);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700448 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800449 }
450
451 @Override
452 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700453 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700454 if (toInstall.isPresent()) {
455 IntentData installData = toInstall.get();
456 log.warn("Failed installation: {} {} on {}",
457 installData.key(), installData.intent(), ops);
458 installData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700459 installData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700460 store.write(installData);
461 }
Sho SHIMIZUd4936252015-04-10 15:03:57 -0700462 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700463 if (toUninstall.isPresent()) {
464 IntentData uninstallData = toUninstall.get();
465 log.warn("Failed withdrawal: {} {} on {}",
466 uninstallData.key(), uninstallData.intent(), ops);
467 uninstallData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700468 uninstallData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700469 store.write(uninstallData);
470 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800471 }
472 });
473
Brian O'Connora7674262015-06-04 13:55:18 -0700474 if (log.isTraceEnabled()) {
475 log.trace("applying intent {} -> {} with {} rules: {}",
476 toUninstall.isPresent() ? toUninstall.get().key() : "<empty>",
477 toInstall.isPresent() ? toInstall.get().key() : "<empty>",
478 operations.stages().stream().mapToLong(i -> i.size()).sum(),
479 operations.stages());
480 }
481
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800482 flowRuleService.apply(operations);
483 }
484
Brian O'Connor66630c82014-10-02 21:08:19 -0700485}