blob: 4dd5e853b3943080f56f2c348d6ab6999763c957 [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;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070024import org.onosproject.event.AbstractListenerManager;
Brian O'Connorabafb502014-12-02 22:26:20 -080025import org.onosproject.core.CoreService;
26import org.onosproject.core.IdGenerator;
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;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070062import static org.onosproject.net.intent.IntentState.*;
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070063import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080064import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
Changhoon Yoon541ef712015-05-23 17:18:34 +090065import static org.onosproject.security.AppGuard.checkPermission;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070066import static org.slf4j.LoggerFactory.getLogger;
Changhoon Yoonb856b812015-08-10 03:47:19 +090067import static org.onosproject.security.AppPermission.Type.*;
68
Brian O'Connor66630c82014-10-02 21:08:19 -070069
70/**
Brian O'Connorce2d8b52015-07-29 16:24:13 -070071 * An implementation of intent service.
Brian O'Connor66630c82014-10-02 21:08:19 -070072 */
73@Component(immediate = true)
74@Service
75public class IntentManager
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070076 extends AbstractListenerManager<IntentEvent, IntentListener>
Brian O'Connor66630c82014-10-02 21:08:19 -070077 implements IntentService, IntentExtensionService {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070078
Sho SHIMIZU8b5051d2014-11-05 11:24:13 -080079 private static final Logger log = getLogger(IntentManager.class);
Brian O'Connor66630c82014-10-02 21:08:19 -070080
81 public static final String INTENT_NULL = "Intent cannot be null";
Ray Milkeyf9af43c2015-02-09 16:45:48 -080082 public static final String INTENT_ID_NULL = "Intent key cannot be null";
Brian O'Connor66630c82014-10-02 21:08:19 -070083
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080084 private static final int NUM_THREADS = 12;
85
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080086 private static final EnumSet<IntentState> RECOMPILE
87 = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070088 private static final EnumSet<IntentState> WITHDRAW
89 = EnumSet.of(WITHDRAW_REQ, WITHDRAWING, WITHDRAWN);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080090
Brian O'Connor520c0522014-11-23 23:50:47 -080091 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected CoreService coreService;
Brian O'Connor66630c82014-10-02 21:08:19 -070093
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected IntentStore store;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -070098 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -070099
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZU214ac322015-02-23 19:30:15 -0800101 protected FlowRuleService flowRuleService;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700102
Brian O'Connordb15b042015-02-04 14:59:28 -0800103 private ExecutorService batchExecutor;
104 private ExecutorService workerExecutor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800105
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800106 private final CompilerRegistry compilerRegistry = new CompilerRegistry();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800107 private final InternalIntentProcessor processor = new InternalIntentProcessor();
Brian O'Connor520c0522014-11-23 23:50:47 -0800108 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
109 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
110 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
111 private IdGenerator idGenerator;
112
Brian O'Connorb499b352015-02-03 16:46:15 -0800113 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800114
Brian O'Connor66630c82014-10-02 21:08:19 -0700115 @Activate
116 public void activate() {
117 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700118 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700119 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorbdc7f002015-02-18 20:49:41 -0800120 batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch"));
121 workerExecutor = newFixedThreadPool(NUM_THREADS, groupedThreads("onos/intent", "worker-%d"));
Brian O'Connor520c0522014-11-23 23:50:47 -0800122 idGenerator = coreService.getIdGenerator("intent-ids");
123 Intent.bindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700124 log.info("Started");
125 }
126
127 @Deactivate
128 public void deactivate() {
129 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700130 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700131 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connordb15b042015-02-04 14:59:28 -0800132 batchExecutor.shutdown();
Brian O'Connor3c58e962015-04-28 23:21:51 -0700133 workerExecutor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800134 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700135 log.info("Stopped");
136 }
137
138 @Override
139 public void submit(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900140 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700141 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800142 IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800143 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700144 }
145
146 @Override
147 public void withdraw(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.WITHDRAW_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800151 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700152 }
153
Brian O'Connor66630c82014-10-02 21:08:19 -0700154 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700155 public void purge(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900156 checkPermission(INTENT_WRITE);
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700157 checkNotNull(intent, INTENT_NULL);
158 IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null);
159 store.addPending(data);
160 }
161
162 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800163 public Intent getIntent(Key key) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900164 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800165 return store.getIntent(key);
166 }
167
168 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700169 public Iterable<Intent> getIntents() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900170 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700171 return store.getIntents();
172 }
173
174 @Override
Thomas Vachuskac46af202015-06-03 16:43:27 -0700175 public Iterable<IntentData> getIntentData() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900176 checkPermission(INTENT_READ);
Thomas Vachuskac46af202015-06-03 16:43:27 -0700177 return store.getIntentData(false, 0);
178 }
179
180 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700181 public long getIntentCount() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900182 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700183 return store.getIntentCount();
184 }
185
186 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800187 public IntentState getIntentState(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900188 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800189 checkNotNull(intentKey, INTENT_ID_NULL);
190 return store.getIntentState(intentKey);
Brian O'Connor66630c82014-10-02 21:08:19 -0700191 }
192
193 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800194 public List<Intent> getInstallableIntents(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.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700198 }
199
200 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800201 public boolean isLocal(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900202 checkPermission(INTENT_READ);
Brian O'Connorbe28a872015-02-19 21:44:37 -0800203 return store.isMaster(intentKey);
204 }
205
206 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700207 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800208 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700209 }
210
211 @Override
212 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800213 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700214 }
215
216 @Override
217 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800218 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700219 }
220
221 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800222 public Iterable<Intent> getPending() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900223 checkPermission(INTENT_READ);
Changhoon Yoon541ef712015-05-23 17:18:34 +0900224
Jonathan Hart34f1e382015-02-24 16:52:23 -0800225 return store.getPending();
226 }
227
Brian O'Connor66630c82014-10-02 21:08:19 -0700228 // Store delegate to re-post events emitted from the store.
229 private class InternalStoreDelegate implements IntentStoreDelegate {
230 @Override
231 public void notify(IntentEvent event) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700232 post(event);
Brian O'Connor66630c82014-10-02 21:08:19 -0700233 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800234
235 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800236 public void process(IntentData data) {
237 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800238 }
Thomas Vachuskac46af202015-06-03 16:43:27 -0700239
240 @Override
241 public void onUpdate(IntentData intentData) {
242 trackerService.trackIntent(intentData);
243 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700244 }
245
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800246 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800247 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800248 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800249 for (Key key : intentKeys) {
250 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800251 if (intent == null) {
252 continue;
253 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800254 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800255 }
256
Jonathan Hart0cca3e82015-09-23 17:54:11 -0700257 if (compileAllFailed) {
258 // If required, compile all currently failed intents.
259 for (Intent intent : getIntents()) {
260 IntentState state = getIntentState(intent.key());
261 if (RECOMPILE.contains(state) || intentAllowsPartialFailure(intent)) {
262 if (WITHDRAW.contains(state)) {
263 withdraw(intent);
264 } else {
265 submit(intent);
266 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800267 }
268 }
269 }
270
Brian O'Connorb499b352015-02-03 16:46:15 -0800271 //FIXME
272// for (ApplicationId appId : batches.keySet()) {
273// if (batchService.isLocalLeader(appId)) {
274// execute(batches.get(appId).build());
275// }
276// }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800277 }
278
tom95329eb2014-10-06 08:40:06 -0700279 // Topology change delegate
280 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
281 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800282 public void triggerCompile(Iterable<Key> intentKeys,
tom85258ee2014-10-07 00:10:02 -0700283 boolean compileAllFailed) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800284 buildAndSubmitBatches(intentKeys, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700285 }
tom95329eb2014-10-06 08:40:06 -0700286 }
tom85258ee2014-10-07 00:10:02 -0700287
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800288 private CompletableFuture<FinalIntentProcessPhase> submitIntentData(IntentData data) {
Sho SHIMIZU0cb6fe62015-02-23 16:39:57 -0800289 IntentData current = store.getIntentData(data.key());
Sho SHIMIZUce49b602015-02-23 19:15:49 -0800290 IntentProcessPhase initial = newInitialPhase(processor, data, current);
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800291 return CompletableFuture.supplyAsync(() -> {
Sho SHIMIZU89925242016-01-13 14:20:34 -0800292 Optional<IntentProcessPhase> currentPhase = Optional.of(initial);
293 IntentProcessPhase previousPhase = initial;
294
295 while (currentPhase.isPresent()) {
296 previousPhase = currentPhase.get();
297 currentPhase = previousPhase.execute();
298 }
299 return (FinalIntentProcessPhase) previousPhase;
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800300 }, workerExecutor);
Sho SHIMIZU8d9d1362015-02-04 12:28:15 -0800301 }
302
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700303 private class InternalBatchDelegate implements IntentBatchDelegate {
304 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800305 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800306 log.debug("Execute {} operation(s).", operations.size());
307 log.trace("Execute operations: {}", operations);
Sho SHIMIZU94b03b12015-04-10 14:53:13 -0700308
309 // batchExecutor is single-threaded, so only one batch is in flight at a time
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800310 batchExecutor.execute(() -> {
311 try {
312 /*
313 1. wrap each intentdata in a runnable and submit
314 2. wait for completion of all the work
315 3. accumulate results and submit batch write of IntentData to store
316 (we can also try to update these individually)
317 */
318 submitUpdates(waitForFutures(createIntentUpdates(operations)));
319 } catch (Exception e) {
320 log.error("Error submitting batches:", e);
321 // FIXME incomplete Intents should be cleaned up
322 // (transition to FAILED, etc.)
323
324 // the batch has failed
325 // TODO: maybe we should do more?
326 log.error("Walk the plank, matey...");
327 //FIXME
328// batchService.removeIntentOperations(data);
329 }
330 accumulator.ready();
331 });
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700332 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700333 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800334
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800335 private List<CompletableFuture<FinalIntentProcessPhase>> createIntentUpdates(Collection<IntentData> data) {
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800336 return data.stream()
337 .map(IntentManager.this::submitIntentData)
338 .collect(Collectors.toList());
339 }
340
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800341 private List<FinalIntentProcessPhase> waitForFutures(List<CompletableFuture<FinalIntentProcessPhase>> futures) {
Sho SHIMIZUab541a52016-01-13 23:29:32 -0800342 return futures.stream()
343 .map(x -> x.exceptionally(e -> {
344 //FIXME
345 log.warn("Future failed: {}", e);
346 return null;
347 }))
348 .map(CompletableFuture::join)
349 .filter(Objects::nonNull)
350 .collect(Collectors.toList());
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800351 }
352
353 private void submitUpdates(List<FinalIntentProcessPhase> updates) {
354 store.batchWrite(updates.stream()
355 .map(FinalIntentProcessPhase::data)
356 .collect(Collectors.toList()));
357 }
358
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800359 private class InternalIntentProcessor implements IntentProcessor {
360 @Override
361 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
362 return compilerRegistry.compile(intent, previousInstallables);
363 }
364
365 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700366 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700367 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800368 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700369 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800370
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700371 private enum Direction {
372 ADD,
373 REMOVE
374 }
375
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700376 private void applyIntentData(Optional<IntentData> intentData,
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700377 FlowRuleOperations.Builder builder,
378 Direction direction) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700379 if (!intentData.isPresent()) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700380 return;
381 }
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700382 IntentData data = intentData.get();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700383
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700384 List<Intent> intentsToApply = data.installables();
385 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
386 throw new IllegalStateException("installable intents must be FlowRuleIntent");
387 }
388
389 if (direction == Direction.ADD) {
390 trackerService.addTrackedResources(data.key(), data.intent().resources());
391 intentsToApply.forEach(installable ->
392 trackerService.addTrackedResources(data.key(), installable.resources()));
393 } else {
394 trackerService.removeTrackedResources(data.key(), data.intent().resources());
395 intentsToApply.forEach(installable ->
396 trackerService.removeTrackedResources(data.intent().key(),
397 installable.resources()));
398 }
399
400 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
401 builder.newStage();
402
403 List<Collection<FlowRule>> stages = intentsToApply.stream()
404 .map(x -> (FlowRuleIntent) x)
405 .map(FlowRuleIntent::flowRules)
406 .collect(Collectors.toList());
407
408 for (Collection<FlowRule> rules : stages) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700409 if (direction == Direction.ADD) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700410 rules.forEach(builder::add);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700411 } else {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700412 rules.forEach(builder::remove);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700413 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800414 }
415
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800416 }
417
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700418 private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800419 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800420
421 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700422 applyIntentData(toUninstall, builder, Direction.REMOVE);
423 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800424
425 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
426 @Override
427 public void onSuccess(FlowRuleOperations ops) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700428 if (toInstall.isPresent()) {
429 IntentData installData = toInstall.get();
430 log.debug("Completed installing: {}", installData.key());
431 installData.setState(INSTALLED);
432 store.write(installData);
433 } else if (toUninstall.isPresent()) {
434 IntentData uninstallData = toUninstall.get();
435 log.debug("Completed withdrawing: {}", uninstallData.key());
436 switch (uninstallData.request()) {
437 case INSTALL_REQ:
438 uninstallData.setState(FAILED);
439 break;
440 case WITHDRAW_REQ:
441 default: //TODO "default" case should not happen
442 uninstallData.setState(WITHDRAWN);
443 break;
444 }
445 store.write(uninstallData);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700446 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800447 }
448
449 @Override
450 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700451 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700452 if (toInstall.isPresent()) {
453 IntentData installData = toInstall.get();
454 log.warn("Failed installation: {} {} on {}",
455 installData.key(), installData.intent(), ops);
456 installData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700457 installData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700458 store.write(installData);
459 }
Sho SHIMIZUd4936252015-04-10 15:03:57 -0700460 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700461 if (toUninstall.isPresent()) {
462 IntentData uninstallData = toUninstall.get();
463 log.warn("Failed withdrawal: {} {} on {}",
464 uninstallData.key(), uninstallData.intent(), ops);
465 uninstallData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700466 uninstallData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700467 store.write(uninstallData);
468 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800469 }
470 });
471
Brian O'Connora7674262015-06-04 13:55:18 -0700472 if (log.isTraceEnabled()) {
473 log.trace("applying intent {} -> {} with {} rules: {}",
474 toUninstall.isPresent() ? toUninstall.get().key() : "<empty>",
475 toInstall.isPresent() ? toInstall.get().key() : "<empty>",
476 operations.stages().stream().mapToLong(i -> i.size()).sum(),
477 operations.stages());
478 }
479
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800480 flowRuleService.apply(operations);
481 }
482
Brian O'Connor66630c82014-10-02 21:08:19 -0700483}