blob: c9d6e56a0f2665db8611615be4ea040a70df4c6b [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;
Sho SHIMIZUe0981722016-01-14 16:02:48 -080024import org.onlab.util.Tools;
Brian O'Connorabafb502014-12-02 22:26:20 -080025import org.onosproject.core.CoreService;
26import org.onosproject.core.IdGenerator;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080027import org.onosproject.event.AbstractListenerManager;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080028import org.onosproject.net.flow.FlowRule;
Brian O'Connor0e271dc2015-02-04 18:20:25 -080029import org.onosproject.net.flow.FlowRuleOperations;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080030import org.onosproject.net.flow.FlowRuleOperationsContext;
Brian O'Connorabafb502014-12-02 22:26:20 -080031import org.onosproject.net.flow.FlowRuleService;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080032import org.onosproject.net.intent.FlowRuleIntent;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.net.intent.Intent;
34import org.onosproject.net.intent.IntentBatchDelegate;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.intent.IntentCompiler;
Brian O'Connorcff03322015-02-03 15:28:59 -080036import org.onosproject.net.intent.IntentData;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.net.intent.IntentEvent;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.net.intent.IntentExtensionService;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.intent.IntentListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.net.intent.IntentService;
41import org.onosproject.net.intent.IntentState;
42import org.onosproject.net.intent.IntentStore;
Brian O'Connorabafb502014-12-02 22:26:20 -080043import org.onosproject.net.intent.IntentStoreDelegate;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080044import org.onosproject.net.intent.Key;
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -080045import org.onosproject.net.intent.impl.phase.FinalIntentProcessPhase;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080046import org.onosproject.net.intent.impl.phase.IntentProcessPhase;
Naoki Shiotabbc7ead2016-01-20 14:10:38 -080047import org.onosproject.net.newresource.ResourceService;
Brian O'Connor66630c82014-10-02 21:08:19 -070048import org.slf4j.Logger;
49
Brian O'Connorf0c5a052015-04-27 00:34:53 -070050import java.util.Collection;
51import java.util.EnumSet;
52import java.util.List;
53import java.util.Map;
Sho SHIMIZUab541a52016-01-13 23:29:32 -080054import java.util.Objects;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070055import java.util.Optional;
Sho SHIMIZUad8ab272016-01-13 22:08:58 -080056import java.util.concurrent.CompletableFuture;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070057import java.util.concurrent.ExecutorService;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070058import java.util.stream.Collectors;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070059
Brian O'Connorfa81eae2014-10-30 13:20:05 -070060import static com.google.common.base.Preconditions.checkNotNull;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080061import static java.util.concurrent.Executors.newFixedThreadPool;
Brian O'Connordb15b042015-02-04 14:59:28 -080062import static java.util.concurrent.Executors.newSingleThreadExecutor;
Brian O'Connorbdc7f002015-02-18 20:49:41 -080063import static org.onlab.util.Tools.groupedThreads;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080064import static org.onosproject.net.intent.IntentState.CORRUPT;
65import static org.onosproject.net.intent.IntentState.FAILED;
66import static org.onosproject.net.intent.IntentState.INSTALLED;
67import static org.onosproject.net.intent.IntentState.INSTALL_REQ;
68import static org.onosproject.net.intent.IntentState.WITHDRAWING;
69import static org.onosproject.net.intent.IntentState.WITHDRAWN;
70import static org.onosproject.net.intent.IntentState.WITHDRAW_REQ;
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070071import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080072import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
Changhoon Yoon541ef712015-05-23 17:18:34 +090073import static org.onosproject.security.AppGuard.checkPermission;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080074import static org.onosproject.security.AppPermission.Type.INTENT_READ;
75import static org.onosproject.security.AppPermission.Type.INTENT_WRITE;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070076import static org.slf4j.LoggerFactory.getLogger;
Changhoon Yoonb856b812015-08-10 03:47:19 +090077
Brian O'Connor66630c82014-10-02 21:08:19 -070078
79/**
Brian O'Connorce2d8b52015-07-29 16:24:13 -070080 * An implementation of intent service.
Brian O'Connor66630c82014-10-02 21:08:19 -070081 */
82@Component(immediate = true)
83@Service
84public class IntentManager
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070085 extends AbstractListenerManager<IntentEvent, IntentListener>
Brian O'Connor66630c82014-10-02 21:08:19 -070086 implements IntentService, IntentExtensionService {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070087
Sho SHIMIZU8b5051d2014-11-05 11:24:13 -080088 private static final Logger log = getLogger(IntentManager.class);
Brian O'Connor66630c82014-10-02 21:08:19 -070089
90 public static final String INTENT_NULL = "Intent cannot be null";
Ray Milkeyf9af43c2015-02-09 16:45:48 -080091 public static final String INTENT_ID_NULL = "Intent key cannot be null";
Brian O'Connor66630c82014-10-02 21:08:19 -070092
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080093 private static final int NUM_THREADS = 12;
94
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080095 private static final EnumSet<IntentState> RECOMPILE
96 = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070097 private static final EnumSet<IntentState> WITHDRAW
98 = EnumSet.of(WITHDRAW_REQ, WITHDRAWING, WITHDRAWN);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080099
Brian O'Connor520c0522014-11-23 23:50:47 -0800100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected CoreService coreService;
Brian O'Connor66630c82014-10-02 21:08:19 -0700102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected IntentStore store;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -0700107 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -0700108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZU214ac322015-02-23 19:30:15 -0800110 protected FlowRuleService flowRuleService;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700111
Naoki Shiotabbc7ead2016-01-20 14:10:38 -0800112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected ResourceService resourceService;
114
Brian O'Connordb15b042015-02-04 14:59:28 -0800115 private ExecutorService batchExecutor;
116 private ExecutorService workerExecutor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800117
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800118 private final CompilerRegistry compilerRegistry = new CompilerRegistry();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800119 private final InternalIntentProcessor processor = new InternalIntentProcessor();
Brian O'Connor520c0522014-11-23 23:50:47 -0800120 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
121 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
122 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
123 private IdGenerator idGenerator;
124
Brian O'Connorb499b352015-02-03 16:46:15 -0800125 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800126
Brian O'Connor66630c82014-10-02 21:08:19 -0700127 @Activate
128 public void activate() {
129 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700130 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700131 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorbdc7f002015-02-18 20:49:41 -0800132 batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch"));
133 workerExecutor = newFixedThreadPool(NUM_THREADS, groupedThreads("onos/intent", "worker-%d"));
Brian O'Connor520c0522014-11-23 23:50:47 -0800134 idGenerator = coreService.getIdGenerator("intent-ids");
135 Intent.bindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700136 log.info("Started");
137 }
138
139 @Deactivate
140 public void deactivate() {
141 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700142 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700143 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connordb15b042015-02-04 14:59:28 -0800144 batchExecutor.shutdown();
Brian O'Connor3c58e962015-04-28 23:21:51 -0700145 workerExecutor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800146 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700147 log.info("Stopped");
148 }
149
150 @Override
151 public void submit(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900152 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700153 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800154 IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800155 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700156 }
157
158 @Override
159 public void withdraw(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900160 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700161 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800162 IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800163 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700164 }
165
Brian O'Connor66630c82014-10-02 21:08:19 -0700166 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700167 public void purge(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900168 checkPermission(INTENT_WRITE);
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700169 checkNotNull(intent, INTENT_NULL);
170 IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null);
171 store.addPending(data);
172 }
173
174 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800175 public Intent getIntent(Key key) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900176 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800177 return store.getIntent(key);
178 }
179
180 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700181 public Iterable<Intent> getIntents() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900182 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700183 return store.getIntents();
184 }
185
186 @Override
Thomas Vachuskac46af202015-06-03 16:43:27 -0700187 public Iterable<IntentData> getIntentData() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900188 checkPermission(INTENT_READ);
Thomas Vachuskac46af202015-06-03 16:43:27 -0700189 return store.getIntentData(false, 0);
190 }
191
192 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700193 public long getIntentCount() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900194 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700195 return store.getIntentCount();
196 }
197
198 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800199 public IntentState getIntentState(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900200 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800201 checkNotNull(intentKey, INTENT_ID_NULL);
202 return store.getIntentState(intentKey);
Brian O'Connor66630c82014-10-02 21:08:19 -0700203 }
204
205 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800206 public List<Intent> getInstallableIntents(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900207 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800208 checkNotNull(intentKey, INTENT_ID_NULL);
209 return store.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700210 }
211
212 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800213 public boolean isLocal(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900214 checkPermission(INTENT_READ);
Brian O'Connorbe28a872015-02-19 21:44:37 -0800215 return store.isMaster(intentKey);
216 }
217
218 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700219 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800220 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700221 }
222
223 @Override
224 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800225 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700226 }
227
228 @Override
229 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800230 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700231 }
232
233 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800234 public Iterable<Intent> getPending() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900235 checkPermission(INTENT_READ);
Changhoon Yoon541ef712015-05-23 17:18:34 +0900236
Jonathan Hart34f1e382015-02-24 16:52:23 -0800237 return store.getPending();
238 }
239
Brian O'Connor66630c82014-10-02 21:08:19 -0700240 // Store delegate to re-post events emitted from the store.
241 private class InternalStoreDelegate implements IntentStoreDelegate {
242 @Override
243 public void notify(IntentEvent event) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700244 post(event);
Naoki Shiotabbc7ead2016-01-20 14:10:38 -0800245 switch (event.type()) {
246 case WITHDRAWN:
247 // release resources allocated to withdrawn intent
248 if (!resourceService.release(event.subject().id())) {
249 log.error("Failed to release resources allocated to {}", event.subject().id());
250 }
251 break;
252 default:
253 break;
254 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700255 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800256
257 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800258 public void process(IntentData data) {
259 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800260 }
Thomas Vachuskac46af202015-06-03 16:43:27 -0700261
262 @Override
263 public void onUpdate(IntentData intentData) {
264 trackerService.trackIntent(intentData);
265 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700266 }
267
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800268 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800269 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800270 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800271 for (Key key : intentKeys) {
272 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800273 if (intent == null) {
274 continue;
275 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800276 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800277 }
278
Jonathan Hart0cca3e82015-09-23 17:54:11 -0700279 if (compileAllFailed) {
280 // If required, compile all currently failed intents.
281 for (Intent intent : getIntents()) {
282 IntentState state = getIntentState(intent.key());
283 if (RECOMPILE.contains(state) || intentAllowsPartialFailure(intent)) {
284 if (WITHDRAW.contains(state)) {
285 withdraw(intent);
286 } else {
287 submit(intent);
288 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800289 }
290 }
291 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800292 }
293
tom95329eb2014-10-06 08:40:06 -0700294 // Topology change delegate
295 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
296 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800297 public void triggerCompile(Iterable<Key> intentKeys,
tom85258ee2014-10-07 00:10:02 -0700298 boolean compileAllFailed) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800299 buildAndSubmitBatches(intentKeys, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700300 }
tom95329eb2014-10-06 08:40:06 -0700301 }
tom85258ee2014-10-07 00:10:02 -0700302
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 SHIMIZU489aa9b2016-01-14 17:19:32 -0800310 CompletableFuture.runAsync(() -> {
Sho SHIMIZU8f2b7772016-01-14 18:17:44 -0800311 // process intent until the phase reaches one of the final phases
312 List<CompletableFuture<IntentData>> futures = operations.stream()
313 .map(x -> CompletableFuture.completedFuture(x)
314 .thenApply(IntentManager.this::createInitialPhase)
Sho SHIMIZU4a141852016-01-14 18:55:40 -0800315 .thenApplyAsync(IntentProcessPhase::process, workerExecutor)
Sho SHIMIZU8f2b7772016-01-14 18:17:44 -0800316 .thenApply(FinalIntentProcessPhase::data)
317 .exceptionally(e -> {
318 //FIXME
319 log.warn("Future failed: {}", e);
320 return null;
321 })).collect(Collectors.toList());
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800322
Sho SHIMIZU8f2b7772016-01-14 18:17:44 -0800323 // write multiple data to store in order
324 store.batchWrite(Tools.allOf(futures).join().stream()
325 .filter(Objects::nonNull)
326 .collect(Collectors.toList()));
327 }, batchExecutor).exceptionally(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...");
Sho SHIMIZU8f2b7772016-01-14 18:17:44 -0800335 return null;
336 }).thenRun(accumulator::ready);
337
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700338 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700339 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800340
Sho SHIMIZUc88b85e2016-01-14 18:45:14 -0800341 private IntentProcessPhase createInitialPhase(IntentData data) {
342 IntentData current = store.getIntentData(data.key());
343 return newInitialPhase(processor, data, current);
344 }
345
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800346 private class InternalIntentProcessor implements IntentProcessor {
347 @Override
348 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
349 return compilerRegistry.compile(intent, previousInstallables);
350 }
351
352 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700353 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700354 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800355 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700356 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800357
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700358 private enum Direction {
359 ADD,
360 REMOVE
361 }
362
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700363 private void applyIntentData(Optional<IntentData> intentData,
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700364 FlowRuleOperations.Builder builder,
365 Direction direction) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700366 if (!intentData.isPresent()) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700367 return;
368 }
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700369 IntentData data = intentData.get();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700370
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700371 List<Intent> intentsToApply = data.installables();
372 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
373 throw new IllegalStateException("installable intents must be FlowRuleIntent");
374 }
375
376 if (direction == Direction.ADD) {
377 trackerService.addTrackedResources(data.key(), data.intent().resources());
378 intentsToApply.forEach(installable ->
379 trackerService.addTrackedResources(data.key(), installable.resources()));
380 } else {
381 trackerService.removeTrackedResources(data.key(), data.intent().resources());
382 intentsToApply.forEach(installable ->
383 trackerService.removeTrackedResources(data.intent().key(),
384 installable.resources()));
385 }
386
387 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
388 builder.newStage();
389
390 List<Collection<FlowRule>> stages = intentsToApply.stream()
391 .map(x -> (FlowRuleIntent) x)
392 .map(FlowRuleIntent::flowRules)
393 .collect(Collectors.toList());
394
395 for (Collection<FlowRule> rules : stages) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700396 if (direction == Direction.ADD) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700397 rules.forEach(builder::add);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700398 } else {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700399 rules.forEach(builder::remove);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700400 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800401 }
402
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800403 }
404
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700405 private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800406 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800407
408 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700409 applyIntentData(toUninstall, builder, Direction.REMOVE);
410 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800411
412 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
413 @Override
414 public void onSuccess(FlowRuleOperations ops) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700415 if (toInstall.isPresent()) {
416 IntentData installData = toInstall.get();
417 log.debug("Completed installing: {}", installData.key());
418 installData.setState(INSTALLED);
419 store.write(installData);
420 } else if (toUninstall.isPresent()) {
421 IntentData uninstallData = toUninstall.get();
422 log.debug("Completed withdrawing: {}", uninstallData.key());
423 switch (uninstallData.request()) {
424 case INSTALL_REQ:
425 uninstallData.setState(FAILED);
426 break;
427 case WITHDRAW_REQ:
428 default: //TODO "default" case should not happen
429 uninstallData.setState(WITHDRAWN);
430 break;
431 }
432 store.write(uninstallData);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700433 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800434 }
435
436 @Override
437 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700438 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700439 if (toInstall.isPresent()) {
440 IntentData installData = toInstall.get();
441 log.warn("Failed installation: {} {} on {}",
442 installData.key(), installData.intent(), ops);
443 installData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700444 installData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700445 store.write(installData);
446 }
Sho SHIMIZUd4936252015-04-10 15:03:57 -0700447 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700448 if (toUninstall.isPresent()) {
449 IntentData uninstallData = toUninstall.get();
450 log.warn("Failed withdrawal: {} {} on {}",
451 uninstallData.key(), uninstallData.intent(), ops);
452 uninstallData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700453 uninstallData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700454 store.write(uninstallData);
455 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800456 }
457 });
458
Brian O'Connora7674262015-06-04 13:55:18 -0700459 if (log.isTraceEnabled()) {
460 log.trace("applying intent {} -> {} with {} rules: {}",
Sho SHIMIZU98c0a392016-01-14 18:40:53 -0800461 toUninstall.map(x -> x.key().toString()).orElse("<empty>"),
462 toInstall.map(x -> x.key().toString()).orElse("<empty>"),
463 operations.stages().stream().mapToLong(i -> i.size()).sum(),
464 operations.stages());
Brian O'Connora7674262015-06-04 13:55:18 -0700465 }
466
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800467 flowRuleService.apply(operations);
468 }
469
Brian O'Connor66630c82014-10-02 21:08:19 -0700470}