blob: bc8d342923732c0125a9bab2b82852b32a234d06 [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;
Brian O'Connorabafb502014-12-02 22:26:20 -080024import org.onosproject.core.CoreService;
25import org.onosproject.core.IdGenerator;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080026import org.onosproject.event.AbstractListenerManager;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080027import org.onosproject.net.flow.FlowRule;
Brian O'Connor0e271dc2015-02-04 18:20:25 -080028import org.onosproject.net.flow.FlowRuleOperations;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080029import org.onosproject.net.flow.FlowRuleOperationsContext;
Brian O'Connorabafb502014-12-02 22:26:20 -080030import org.onosproject.net.flow.FlowRuleService;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080031import org.onosproject.net.intent.FlowRuleIntent;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.net.intent.Intent;
33import org.onosproject.net.intent.IntentBatchDelegate;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.net.intent.IntentCompiler;
Brian O'Connorcff03322015-02-03 15:28:59 -080035import org.onosproject.net.intent.IntentData;
Brian O'Connorabafb502014-12-02 22:26:20 -080036import org.onosproject.net.intent.IntentEvent;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.net.intent.IntentExtensionService;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.net.intent.IntentListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.intent.IntentService;
40import org.onosproject.net.intent.IntentState;
41import org.onosproject.net.intent.IntentStore;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.net.intent.IntentStoreDelegate;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080043import org.onosproject.net.intent.Key;
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -080044import org.onosproject.net.intent.impl.phase.FinalIntentProcessPhase;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080045import org.onosproject.net.intent.impl.phase.IntentProcessPhase;
Brian O'Connor66630c82014-10-02 21:08:19 -070046import org.slf4j.Logger;
47
Brian O'Connorf0c5a052015-04-27 00:34:53 -070048import java.util.Collection;
49import java.util.EnumSet;
50import java.util.List;
51import java.util.Map;
Sho SHIMIZUab541a52016-01-13 23:29:32 -080052import java.util.Objects;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070053import 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.ExecutorService;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070056import java.util.stream.Collectors;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070057
Brian O'Connorfa81eae2014-10-30 13:20:05 -070058import static com.google.common.base.Preconditions.checkNotNull;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080059import static java.util.concurrent.Executors.newFixedThreadPool;
Brian O'Connordb15b042015-02-04 14:59:28 -080060import static java.util.concurrent.Executors.newSingleThreadExecutor;
Brian O'Connorbdc7f002015-02-18 20:49:41 -080061import static org.onlab.util.Tools.groupedThreads;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080062import static org.onosproject.net.intent.IntentState.CORRUPT;
63import static org.onosproject.net.intent.IntentState.FAILED;
64import static org.onosproject.net.intent.IntentState.INSTALLED;
65import static org.onosproject.net.intent.IntentState.INSTALL_REQ;
66import static org.onosproject.net.intent.IntentState.WITHDRAWING;
67import static org.onosproject.net.intent.IntentState.WITHDRAWN;
68import static org.onosproject.net.intent.IntentState.WITHDRAW_REQ;
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070069import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080070import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
Changhoon Yoon541ef712015-05-23 17:18:34 +090071import static org.onosproject.security.AppGuard.checkPermission;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080072import static org.onosproject.security.AppPermission.Type.INTENT_READ;
73import static org.onosproject.security.AppPermission.Type.INTENT_WRITE;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070074import static org.slf4j.LoggerFactory.getLogger;
Changhoon Yoonb856b812015-08-10 03:47:19 +090075
Brian O'Connor66630c82014-10-02 21:08:19 -070076
77/**
Brian O'Connorce2d8b52015-07-29 16:24:13 -070078 * An implementation of intent service.
Brian O'Connor66630c82014-10-02 21:08:19 -070079 */
80@Component(immediate = true)
81@Service
82public class IntentManager
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070083 extends AbstractListenerManager<IntentEvent, IntentListener>
Brian O'Connor66630c82014-10-02 21:08:19 -070084 implements IntentService, IntentExtensionService {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070085
Sho SHIMIZU8b5051d2014-11-05 11:24:13 -080086 private static final Logger log = getLogger(IntentManager.class);
Brian O'Connor66630c82014-10-02 21:08:19 -070087
88 public static final String INTENT_NULL = "Intent cannot be null";
Ray Milkeyf9af43c2015-02-09 16:45:48 -080089 public static final String INTENT_ID_NULL = "Intent key cannot be null";
Brian O'Connor66630c82014-10-02 21:08:19 -070090
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080091 private static final int NUM_THREADS = 12;
92
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080093 private static final EnumSet<IntentState> RECOMPILE
94 = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070095 private static final EnumSet<IntentState> WITHDRAW
96 = EnumSet.of(WITHDRAW_REQ, WITHDRAWING, WITHDRAWN);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080097
Brian O'Connor520c0522014-11-23 23:50:47 -080098 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected CoreService coreService;
Brian O'Connor66630c82014-10-02 21:08:19 -0700100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected IntentStore store;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -0700105 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -0700106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZU214ac322015-02-23 19:30:15 -0800108 protected FlowRuleService flowRuleService;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700109
Brian O'Connordb15b042015-02-04 14:59:28 -0800110 private ExecutorService batchExecutor;
111 private ExecutorService workerExecutor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800112
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800113 private final CompilerRegistry compilerRegistry = new CompilerRegistry();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800114 private final InternalIntentProcessor processor = new InternalIntentProcessor();
Brian O'Connor520c0522014-11-23 23:50:47 -0800115 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
116 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
117 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
118 private IdGenerator idGenerator;
119
Brian O'Connorb499b352015-02-03 16:46:15 -0800120 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800121
Brian O'Connor66630c82014-10-02 21:08:19 -0700122 @Activate
123 public void activate() {
124 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700125 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700126 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorbdc7f002015-02-18 20:49:41 -0800127 batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch"));
128 workerExecutor = newFixedThreadPool(NUM_THREADS, groupedThreads("onos/intent", "worker-%d"));
Brian O'Connor520c0522014-11-23 23:50:47 -0800129 idGenerator = coreService.getIdGenerator("intent-ids");
130 Intent.bindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700131 log.info("Started");
132 }
133
134 @Deactivate
135 public void deactivate() {
136 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700137 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700138 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connordb15b042015-02-04 14:59:28 -0800139 batchExecutor.shutdown();
Brian O'Connor3c58e962015-04-28 23:21:51 -0700140 workerExecutor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800141 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700142 log.info("Stopped");
143 }
144
145 @Override
146 public void submit(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900147 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700148 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800149 IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800150 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700151 }
152
153 @Override
154 public void withdraw(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900155 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700156 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800157 IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800158 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700159 }
160
Brian O'Connor66630c82014-10-02 21:08:19 -0700161 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700162 public void purge(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900163 checkPermission(INTENT_WRITE);
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700164 checkNotNull(intent, INTENT_NULL);
165 IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null);
166 store.addPending(data);
167 }
168
169 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800170 public Intent getIntent(Key key) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900171 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800172 return store.getIntent(key);
173 }
174
175 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700176 public Iterable<Intent> getIntents() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900177 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700178 return store.getIntents();
179 }
180
181 @Override
Thomas Vachuskac46af202015-06-03 16:43:27 -0700182 public Iterable<IntentData> getIntentData() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900183 checkPermission(INTENT_READ);
Thomas Vachuskac46af202015-06-03 16:43:27 -0700184 return store.getIntentData(false, 0);
185 }
186
187 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700188 public long getIntentCount() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900189 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700190 return store.getIntentCount();
191 }
192
193 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800194 public IntentState getIntentState(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900195 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800196 checkNotNull(intentKey, INTENT_ID_NULL);
197 return store.getIntentState(intentKey);
Brian O'Connor66630c82014-10-02 21:08:19 -0700198 }
199
200 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800201 public List<Intent> getInstallableIntents(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900202 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800203 checkNotNull(intentKey, INTENT_ID_NULL);
204 return store.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700205 }
206
207 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800208 public boolean isLocal(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900209 checkPermission(INTENT_READ);
Brian O'Connorbe28a872015-02-19 21:44:37 -0800210 return store.isMaster(intentKey);
211 }
212
213 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700214 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800215 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700216 }
217
218 @Override
219 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800220 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700221 }
222
223 @Override
224 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800225 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700226 }
227
228 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800229 public Iterable<Intent> getPending() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900230 checkPermission(INTENT_READ);
Changhoon Yoon541ef712015-05-23 17:18:34 +0900231
Jonathan Hart34f1e382015-02-24 16:52:23 -0800232 return store.getPending();
233 }
234
Brian O'Connor66630c82014-10-02 21:08:19 -0700235 // Store delegate to re-post events emitted from the store.
236 private class InternalStoreDelegate implements IntentStoreDelegate {
237 @Override
238 public void notify(IntentEvent event) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700239 post(event);
Brian O'Connor66630c82014-10-02 21:08:19 -0700240 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800241
242 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800243 public void process(IntentData data) {
244 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800245 }
Thomas Vachuskac46af202015-06-03 16:43:27 -0700246
247 @Override
248 public void onUpdate(IntentData intentData) {
249 trackerService.trackIntent(intentData);
250 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700251 }
252
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800253 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800254 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800255 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800256 for (Key key : intentKeys) {
257 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800258 if (intent == null) {
259 continue;
260 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800261 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800262 }
263
Jonathan Hart0cca3e82015-09-23 17:54:11 -0700264 if (compileAllFailed) {
265 // If required, compile all currently failed intents.
266 for (Intent intent : getIntents()) {
267 IntentState state = getIntentState(intent.key());
268 if (RECOMPILE.contains(state) || intentAllowsPartialFailure(intent)) {
269 if (WITHDRAW.contains(state)) {
270 withdraw(intent);
271 } else {
272 submit(intent);
273 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800274 }
275 }
276 }
277
Brian O'Connorb499b352015-02-03 16:46:15 -0800278 //FIXME
279// for (ApplicationId appId : batches.keySet()) {
280// if (batchService.isLocalLeader(appId)) {
281// execute(batches.get(appId).build());
282// }
283// }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800284 }
285
tom95329eb2014-10-06 08:40:06 -0700286 // Topology change delegate
287 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
288 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800289 public void triggerCompile(Iterable<Key> intentKeys,
tom85258ee2014-10-07 00:10:02 -0700290 boolean compileAllFailed) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800291 buildAndSubmitBatches(intentKeys, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700292 }
tom95329eb2014-10-06 08:40:06 -0700293 }
tom85258ee2014-10-07 00:10:02 -0700294
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800295 private CompletableFuture<FinalIntentProcessPhase> submitIntentData(IntentData data) {
Sho SHIMIZU0cb6fe62015-02-23 16:39:57 -0800296 IntentData current = store.getIntentData(data.key());
Sho SHIMIZUce49b602015-02-23 19:15:49 -0800297 IntentProcessPhase initial = newInitialPhase(processor, data, current);
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800298 return CompletableFuture.supplyAsync(() -> {
Sho SHIMIZU89925242016-01-13 14:20:34 -0800299 Optional<IntentProcessPhase> currentPhase = Optional.of(initial);
300 IntentProcessPhase previousPhase = initial;
301
302 while (currentPhase.isPresent()) {
303 previousPhase = currentPhase.get();
304 currentPhase = previousPhase.execute();
305 }
306 return (FinalIntentProcessPhase) previousPhase;
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800307 }, workerExecutor);
Sho SHIMIZU8d9d1362015-02-04 12:28:15 -0800308 }
309
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700310 private class InternalBatchDelegate implements IntentBatchDelegate {
311 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800312 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800313 log.debug("Execute {} operation(s).", operations.size());
314 log.trace("Execute operations: {}", operations);
Sho SHIMIZU94b03b12015-04-10 14:53:13 -0700315
316 // batchExecutor is single-threaded, so only one batch is in flight at a time
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800317 batchExecutor.execute(() -> {
318 try {
319 /*
320 1. wrap each intentdata in a runnable and submit
321 2. wait for completion of all the work
322 3. accumulate results and submit batch write of IntentData to store
323 (we can also try to update these individually)
324 */
325 submitUpdates(waitForFutures(createIntentUpdates(operations)));
326 } catch (Exception e) {
327 log.error("Error submitting batches:", e);
328 // FIXME incomplete Intents should be cleaned up
329 // (transition to FAILED, etc.)
330
331 // the batch has failed
332 // TODO: maybe we should do more?
333 log.error("Walk the plank, matey...");
334 //FIXME
335// batchService.removeIntentOperations(data);
336 }
337 accumulator.ready();
338 });
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700339 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700340 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800341
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800342 private List<CompletableFuture<FinalIntentProcessPhase>> createIntentUpdates(Collection<IntentData> data) {
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800343 return data.stream()
344 .map(IntentManager.this::submitIntentData)
345 .collect(Collectors.toList());
346 }
347
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800348 private List<FinalIntentProcessPhase> waitForFutures(List<CompletableFuture<FinalIntentProcessPhase>> futures) {
Sho SHIMIZUab541a52016-01-13 23:29:32 -0800349 return futures.stream()
350 .map(x -> x.exceptionally(e -> {
351 //FIXME
352 log.warn("Future failed: {}", e);
353 return null;
354 }))
355 .map(CompletableFuture::join)
356 .filter(Objects::nonNull)
357 .collect(Collectors.toList());
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800358 }
359
360 private void submitUpdates(List<FinalIntentProcessPhase> updates) {
361 store.batchWrite(updates.stream()
362 .map(FinalIntentProcessPhase::data)
363 .collect(Collectors.toList()));
364 }
365
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800366 private class InternalIntentProcessor implements IntentProcessor {
367 @Override
368 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
369 return compilerRegistry.compile(intent, previousInstallables);
370 }
371
372 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700373 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700374 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800375 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700376 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800377
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700378 private enum Direction {
379 ADD,
380 REMOVE
381 }
382
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700383 private void applyIntentData(Optional<IntentData> intentData,
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700384 FlowRuleOperations.Builder builder,
385 Direction direction) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700386 if (!intentData.isPresent()) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700387 return;
388 }
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700389 IntentData data = intentData.get();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700390
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700391 List<Intent> intentsToApply = data.installables();
392 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
393 throw new IllegalStateException("installable intents must be FlowRuleIntent");
394 }
395
396 if (direction == Direction.ADD) {
397 trackerService.addTrackedResources(data.key(), data.intent().resources());
398 intentsToApply.forEach(installable ->
399 trackerService.addTrackedResources(data.key(), installable.resources()));
400 } else {
401 trackerService.removeTrackedResources(data.key(), data.intent().resources());
402 intentsToApply.forEach(installable ->
403 trackerService.removeTrackedResources(data.intent().key(),
404 installable.resources()));
405 }
406
407 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
408 builder.newStage();
409
410 List<Collection<FlowRule>> stages = intentsToApply.stream()
411 .map(x -> (FlowRuleIntent) x)
412 .map(FlowRuleIntent::flowRules)
413 .collect(Collectors.toList());
414
415 for (Collection<FlowRule> rules : stages) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700416 if (direction == Direction.ADD) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700417 rules.forEach(builder::add);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700418 } else {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700419 rules.forEach(builder::remove);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700420 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800421 }
422
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800423 }
424
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700425 private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800426 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800427
428 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700429 applyIntentData(toUninstall, builder, Direction.REMOVE);
430 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800431
432 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
433 @Override
434 public void onSuccess(FlowRuleOperations ops) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700435 if (toInstall.isPresent()) {
436 IntentData installData = toInstall.get();
437 log.debug("Completed installing: {}", installData.key());
438 installData.setState(INSTALLED);
439 store.write(installData);
440 } else if (toUninstall.isPresent()) {
441 IntentData uninstallData = toUninstall.get();
442 log.debug("Completed withdrawing: {}", uninstallData.key());
443 switch (uninstallData.request()) {
444 case INSTALL_REQ:
445 uninstallData.setState(FAILED);
446 break;
447 case WITHDRAW_REQ:
448 default: //TODO "default" case should not happen
449 uninstallData.setState(WITHDRAWN);
450 break;
451 }
452 store.write(uninstallData);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700453 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800454 }
455
456 @Override
457 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700458 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700459 if (toInstall.isPresent()) {
460 IntentData installData = toInstall.get();
461 log.warn("Failed installation: {} {} on {}",
462 installData.key(), installData.intent(), ops);
463 installData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700464 installData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700465 store.write(installData);
466 }
Sho SHIMIZUd4936252015-04-10 15:03:57 -0700467 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700468 if (toUninstall.isPresent()) {
469 IntentData uninstallData = toUninstall.get();
470 log.warn("Failed withdrawal: {} {} on {}",
471 uninstallData.key(), uninstallData.intent(), ops);
472 uninstallData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700473 uninstallData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700474 store.write(uninstallData);
475 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800476 }
477 });
478
Brian O'Connora7674262015-06-04 13:55:18 -0700479 if (log.isTraceEnabled()) {
480 log.trace("applying intent {} -> {} with {} rules: {}",
Sho SHIMIZU98c0a392016-01-14 18:40:53 -0800481 toUninstall.map(x -> x.key().toString()).orElse("<empty>"),
482 toInstall.map(x -> x.key().toString()).orElse("<empty>"),
483 operations.stages().stream().mapToLong(i -> i.size()).sum(),
484 operations.stages());
Brian O'Connora7674262015-06-04 13:55:18 -0700485 }
486
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800487 flowRuleService.apply(operations);
488 }
489
Brian O'Connor66630c82014-10-02 21:08:19 -0700490}