blob: 063199339cda2aaab96b5b9da3371af2c298d305 [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;
Sho SHIMIZU38a47982016-01-13 23:34:31 -080057import java.util.stream.Stream;
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 SHIMIZUad8ab272016-01-13 22:08:58 -0800296 private CompletableFuture<FinalIntentProcessPhase> submitIntentData(IntentData data) {
Sho SHIMIZU0cb6fe62015-02-23 16:39:57 -0800297 IntentData current = store.getIntentData(data.key());
Sho SHIMIZUce49b602015-02-23 19:15:49 -0800298 IntentProcessPhase initial = newInitialPhase(processor, data, current);
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800299 return CompletableFuture.supplyAsync(() -> {
Sho SHIMIZU89925242016-01-13 14:20:34 -0800300 Optional<IntentProcessPhase> currentPhase = Optional.of(initial);
301 IntentProcessPhase previousPhase = initial;
302
303 while (currentPhase.isPresent()) {
304 previousPhase = currentPhase.get();
305 currentPhase = previousPhase.execute();
306 }
307 return (FinalIntentProcessPhase) previousPhase;
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800308 }, workerExecutor);
Sho SHIMIZU8d9d1362015-02-04 12:28:15 -0800309 }
310
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700311 private class InternalBatchDelegate implements IntentBatchDelegate {
312 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800313 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800314 log.debug("Execute {} operation(s).", operations.size());
315 log.trace("Execute operations: {}", operations);
Sho SHIMIZU94b03b12015-04-10 14:53:13 -0700316
317 // batchExecutor is single-threaded, so only one batch is in flight at a time
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800318 batchExecutor.execute(() -> {
319 try {
320 /*
321 1. wrap each intentdata in a runnable and submit
322 2. wait for completion of all the work
323 3. accumulate results and submit batch write of IntentData to store
324 (we can also try to update these individually)
325 */
326 submitUpdates(waitForFutures(createIntentUpdates(operations)));
327 } catch (Exception e) {
328 log.error("Error submitting batches:", e);
329 // FIXME incomplete Intents should be cleaned up
330 // (transition to FAILED, etc.)
331
332 // the batch has failed
333 // TODO: maybe we should do more?
334 log.error("Walk the plank, matey...");
335 //FIXME
336// batchService.removeIntentOperations(data);
337 }
338 accumulator.ready();
339 });
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700340 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700341 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800342
Sho SHIMIZU38a47982016-01-13 23:34:31 -0800343 private Stream<CompletableFuture<FinalIntentProcessPhase>> createIntentUpdates(Collection<IntentData> data) {
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800344 return data.stream()
Sho SHIMIZU38a47982016-01-13 23:34:31 -0800345 .map(IntentManager.this::submitIntentData);
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800346 }
347
Sho SHIMIZU38a47982016-01-13 23:34:31 -0800348 private Stream<FinalIntentProcessPhase> waitForFutures(Stream<CompletableFuture<FinalIntentProcessPhase>> futures) {
349 return futures
Sho SHIMIZUab541a52016-01-13 23:29:32 -0800350 .map(x -> x.exceptionally(e -> {
351 //FIXME
352 log.warn("Future failed: {}", e);
353 return null;
354 }))
355 .map(CompletableFuture::join)
Sho SHIMIZU38a47982016-01-13 23:34:31 -0800356 .filter(Objects::nonNull);
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800357 }
358
Sho SHIMIZU38a47982016-01-13 23:34:31 -0800359 private void submitUpdates(Stream<FinalIntentProcessPhase> updates) {
360 store.batchWrite(updates
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800361 .map(FinalIntentProcessPhase::data)
362 .collect(Collectors.toList()));
363 }
364
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800365 private class InternalIntentProcessor implements IntentProcessor {
366 @Override
367 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
368 return compilerRegistry.compile(intent, previousInstallables);
369 }
370
371 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700372 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700373 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800374 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700375 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800376
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700377 private enum Direction {
378 ADD,
379 REMOVE
380 }
381
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700382 private void applyIntentData(Optional<IntentData> intentData,
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700383 FlowRuleOperations.Builder builder,
384 Direction direction) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700385 if (!intentData.isPresent()) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700386 return;
387 }
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700388 IntentData data = intentData.get();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700389
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700390 List<Intent> intentsToApply = data.installables();
391 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
392 throw new IllegalStateException("installable intents must be FlowRuleIntent");
393 }
394
395 if (direction == Direction.ADD) {
396 trackerService.addTrackedResources(data.key(), data.intent().resources());
397 intentsToApply.forEach(installable ->
398 trackerService.addTrackedResources(data.key(), installable.resources()));
399 } else {
400 trackerService.removeTrackedResources(data.key(), data.intent().resources());
401 intentsToApply.forEach(installable ->
402 trackerService.removeTrackedResources(data.intent().key(),
403 installable.resources()));
404 }
405
406 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
407 builder.newStage();
408
409 List<Collection<FlowRule>> stages = intentsToApply.stream()
410 .map(x -> (FlowRuleIntent) x)
411 .map(FlowRuleIntent::flowRules)
412 .collect(Collectors.toList());
413
414 for (Collection<FlowRule> rules : stages) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700415 if (direction == Direction.ADD) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700416 rules.forEach(builder::add);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700417 } else {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700418 rules.forEach(builder::remove);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700419 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800420 }
421
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800422 }
423
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700424 private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800425 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800426
427 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700428 applyIntentData(toUninstall, builder, Direction.REMOVE);
429 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800430
431 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
432 @Override
433 public void onSuccess(FlowRuleOperations ops) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700434 if (toInstall.isPresent()) {
435 IntentData installData = toInstall.get();
436 log.debug("Completed installing: {}", installData.key());
437 installData.setState(INSTALLED);
438 store.write(installData);
439 } else if (toUninstall.isPresent()) {
440 IntentData uninstallData = toUninstall.get();
441 log.debug("Completed withdrawing: {}", uninstallData.key());
442 switch (uninstallData.request()) {
443 case INSTALL_REQ:
444 uninstallData.setState(FAILED);
445 break;
446 case WITHDRAW_REQ:
447 default: //TODO "default" case should not happen
448 uninstallData.setState(WITHDRAWN);
449 break;
450 }
451 store.write(uninstallData);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700452 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800453 }
454
455 @Override
456 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700457 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700458 if (toInstall.isPresent()) {
459 IntentData installData = toInstall.get();
460 log.warn("Failed installation: {} {} on {}",
461 installData.key(), installData.intent(), ops);
462 installData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700463 installData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700464 store.write(installData);
465 }
Sho SHIMIZUd4936252015-04-10 15:03:57 -0700466 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700467 if (toUninstall.isPresent()) {
468 IntentData uninstallData = toUninstall.get();
469 log.warn("Failed withdrawal: {} {} on {}",
470 uninstallData.key(), uninstallData.intent(), ops);
471 uninstallData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700472 uninstallData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700473 store.write(uninstallData);
474 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800475 }
476 });
477
Brian O'Connora7674262015-06-04 13:55:18 -0700478 if (log.isTraceEnabled()) {
479 log.trace("applying intent {} -> {} with {} rules: {}",
Sho SHIMIZU98c0a392016-01-14 18:40:53 -0800480 toUninstall.map(x -> x.key().toString()).orElse("<empty>"),
481 toInstall.map(x -> x.key().toString()).orElse("<empty>"),
482 operations.stages().stream().mapToLong(i -> i.size()).sum(),
483 operations.stages());
Brian O'Connora7674262015-06-04 13:55:18 -0700484 }
485
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800486 flowRuleService.apply(operations);
487 }
488
Brian O'Connor66630c82014-10-02 21:08:19 -0700489}