blob: 68087882620e213aa0728338b8199eba9c1ca75e [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 */
Sho SHIMIZUd7558932016-01-13 23:47:46 -0800325 store.batchWrite(operations.stream()
326 .map(IntentManager.this::submitIntentData)
327 .map(x -> x.exceptionally(e -> {
328 //FIXME
329 log.warn("Future failed: {}", e);
330 return null;
331 }))
332 .map(CompletableFuture::join)
333 .filter(Objects::nonNull)
334 .map(FinalIntentProcessPhase::data)
335 .collect(Collectors.toList()));
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800336 } catch (Exception e) {
337 log.error("Error submitting batches:", e);
338 // FIXME incomplete Intents should be cleaned up
339 // (transition to FAILED, etc.)
340
341 // the batch has failed
342 // TODO: maybe we should do more?
343 log.error("Walk the plank, matey...");
344 //FIXME
345// batchService.removeIntentOperations(data);
346 }
347 accumulator.ready();
348 });
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700349 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700350 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800351
352 private class InternalIntentProcessor implements IntentProcessor {
353 @Override
354 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
355 return compilerRegistry.compile(intent, previousInstallables);
356 }
357
358 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700359 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700360 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800361 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700362 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800363
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700364 private enum Direction {
365 ADD,
366 REMOVE
367 }
368
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700369 private void applyIntentData(Optional<IntentData> intentData,
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700370 FlowRuleOperations.Builder builder,
371 Direction direction) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700372 if (!intentData.isPresent()) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700373 return;
374 }
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700375 IntentData data = intentData.get();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700376
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700377 List<Intent> intentsToApply = data.installables();
378 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
379 throw new IllegalStateException("installable intents must be FlowRuleIntent");
380 }
381
382 if (direction == Direction.ADD) {
383 trackerService.addTrackedResources(data.key(), data.intent().resources());
384 intentsToApply.forEach(installable ->
385 trackerService.addTrackedResources(data.key(), installable.resources()));
386 } else {
387 trackerService.removeTrackedResources(data.key(), data.intent().resources());
388 intentsToApply.forEach(installable ->
389 trackerService.removeTrackedResources(data.intent().key(),
390 installable.resources()));
391 }
392
393 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
394 builder.newStage();
395
396 List<Collection<FlowRule>> stages = intentsToApply.stream()
397 .map(x -> (FlowRuleIntent) x)
398 .map(FlowRuleIntent::flowRules)
399 .collect(Collectors.toList());
400
401 for (Collection<FlowRule> rules : stages) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700402 if (direction == Direction.ADD) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700403 rules.forEach(builder::add);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700404 } else {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700405 rules.forEach(builder::remove);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700406 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800407 }
408
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800409 }
410
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700411 private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800412 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800413
414 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700415 applyIntentData(toUninstall, builder, Direction.REMOVE);
416 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800417
418 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
419 @Override
420 public void onSuccess(FlowRuleOperations ops) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700421 if (toInstall.isPresent()) {
422 IntentData installData = toInstall.get();
423 log.debug("Completed installing: {}", installData.key());
424 installData.setState(INSTALLED);
425 store.write(installData);
426 } else if (toUninstall.isPresent()) {
427 IntentData uninstallData = toUninstall.get();
428 log.debug("Completed withdrawing: {}", uninstallData.key());
429 switch (uninstallData.request()) {
430 case INSTALL_REQ:
431 uninstallData.setState(FAILED);
432 break;
433 case WITHDRAW_REQ:
434 default: //TODO "default" case should not happen
435 uninstallData.setState(WITHDRAWN);
436 break;
437 }
438 store.write(uninstallData);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700439 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800440 }
441
442 @Override
443 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700444 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700445 if (toInstall.isPresent()) {
446 IntentData installData = toInstall.get();
447 log.warn("Failed installation: {} {} on {}",
448 installData.key(), installData.intent(), ops);
449 installData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700450 installData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700451 store.write(installData);
452 }
Sho SHIMIZUd4936252015-04-10 15:03:57 -0700453 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700454 if (toUninstall.isPresent()) {
455 IntentData uninstallData = toUninstall.get();
456 log.warn("Failed withdrawal: {} {} on {}",
457 uninstallData.key(), uninstallData.intent(), ops);
458 uninstallData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700459 uninstallData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700460 store.write(uninstallData);
461 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800462 }
463 });
464
Brian O'Connora7674262015-06-04 13:55:18 -0700465 if (log.isTraceEnabled()) {
466 log.trace("applying intent {} -> {} with {} rules: {}",
Sho SHIMIZU98c0a392016-01-14 18:40:53 -0800467 toUninstall.map(x -> x.key().toString()).orElse("<empty>"),
468 toInstall.map(x -> x.key().toString()).orElse("<empty>"),
469 operations.stages().stream().mapToLong(i -> i.size()).sum(),
470 operations.stages());
Brian O'Connora7674262015-06-04 13:55:18 -0700471 }
472
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800473 flowRuleService.apply(operations);
474 }
475
Brian O'Connor66630c82014-10-02 21:08:19 -0700476}