blob: d97400920a6524a9a1bb63dbc6bdbbff4c780f18 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 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'Connorf0c5a052015-04-27 00:34:53 -070018import com.google.common.collect.ImmutableList;
Brian O'Connor66630c82014-10-02 21:08:19 -070019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070025import org.onosproject.event.AbstractListenerManager;
Brian O'Connorabafb502014-12-02 22:26:20 -080026import org.onosproject.core.CoreService;
27import org.onosproject.core.IdGenerator;
Changhoon Yoon541ef712015-05-23 17:18:34 +090028import org.onosproject.core.Permission;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080029import org.onosproject.net.flow.FlowRule;
Brian O'Connor0e271dc2015-02-04 18:20:25 -080030import org.onosproject.net.flow.FlowRuleOperations;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080031import org.onosproject.net.flow.FlowRuleOperationsContext;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.net.flow.FlowRuleService;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080033import org.onosproject.net.intent.FlowRuleIntent;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.net.intent.Intent;
35import org.onosproject.net.intent.IntentBatchDelegate;
Brian O'Connorabafb502014-12-02 22:26:20 -080036import org.onosproject.net.intent.IntentCompiler;
Brian O'Connorcff03322015-02-03 15:28:59 -080037import org.onosproject.net.intent.IntentData;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.net.intent.IntentEvent;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.intent.IntentExtensionService;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.net.intent.IntentListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080041import org.onosproject.net.intent.IntentService;
42import org.onosproject.net.intent.IntentState;
43import org.onosproject.net.intent.IntentStore;
Brian O'Connorabafb502014-12-02 22:26:20 -080044import org.onosproject.net.intent.IntentStoreDelegate;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080045import org.onosproject.net.intent.Key;
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -080046import org.onosproject.net.intent.impl.phase.FinalIntentProcessPhase;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080047import org.onosproject.net.intent.impl.phase.IntentProcessPhase;
Sho SHIMIZU662c3db2015-02-23 16:59:01 -080048import org.onosproject.net.intent.impl.phase.IntentWorker;
Brian O'Connor66630c82014-10-02 21:08:19 -070049import org.slf4j.Logger;
50
Brian O'Connorf0c5a052015-04-27 00:34:53 -070051import java.util.Collection;
52import java.util.EnumSet;
53import java.util.List;
54import java.util.Map;
55import java.util.Optional;
56import java.util.concurrent.ExecutionException;
57import java.util.concurrent.ExecutorService;
58import java.util.concurrent.Future;
59import java.util.stream.Collectors;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070060
Brian O'Connorfa81eae2014-10-30 13:20:05 -070061import static com.google.common.base.Preconditions.checkNotNull;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080062import static java.util.concurrent.Executors.newFixedThreadPool;
Brian O'Connordb15b042015-02-04 14:59:28 -080063import static java.util.concurrent.Executors.newSingleThreadExecutor;
Brian O'Connorbdc7f002015-02-18 20:49:41 -080064import static org.onlab.util.Tools.groupedThreads;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070065import static org.onosproject.net.intent.IntentState.*;
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070066import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080067import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
Changhoon Yoon541ef712015-05-23 17:18:34 +090068import static org.onosproject.security.AppGuard.checkPermission;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070069import static org.slf4j.LoggerFactory.getLogger;
Brian O'Connor66630c82014-10-02 21:08:19 -070070
71/**
Brian O'Connorce2d8b52015-07-29 16:24:13 -070072 * An implementation of intent service.
Brian O'Connor66630c82014-10-02 21:08:19 -070073 */
74@Component(immediate = true)
75@Service
76public class IntentManager
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070077 extends AbstractListenerManager<IntentEvent, IntentListener>
Brian O'Connor66630c82014-10-02 21:08:19 -070078 implements IntentService, IntentExtensionService {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070079
Sho SHIMIZU8b5051d2014-11-05 11:24:13 -080080 private static final Logger log = getLogger(IntentManager.class);
Brian O'Connor66630c82014-10-02 21:08:19 -070081
82 public static final String INTENT_NULL = "Intent cannot be null";
Ray Milkeyf9af43c2015-02-09 16:45:48 -080083 public static final String INTENT_ID_NULL = "Intent key cannot be null";
Brian O'Connor66630c82014-10-02 21:08:19 -070084
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080085 private static final int NUM_THREADS = 12;
86
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080087 private static final EnumSet<IntentState> RECOMPILE
88 = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070089 private static final EnumSet<IntentState> WITHDRAW
90 = EnumSet.of(WITHDRAW_REQ, WITHDRAWING, WITHDRAWN);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080091
Brian O'Connor520c0522014-11-23 23:50:47 -080092 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected CoreService coreService;
Brian O'Connor66630c82014-10-02 21:08:19 -070094
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected IntentStore store;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -070099 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -0700100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZU214ac322015-02-23 19:30:15 -0800102 protected FlowRuleService flowRuleService;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700103
Brian O'Connordb15b042015-02-04 14:59:28 -0800104 private ExecutorService batchExecutor;
105 private ExecutorService workerExecutor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800106
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800107 private final CompilerRegistry compilerRegistry = new CompilerRegistry();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800108 private final InternalIntentProcessor processor = new InternalIntentProcessor();
Brian O'Connor520c0522014-11-23 23:50:47 -0800109 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
110 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
111 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
112 private IdGenerator idGenerator;
113
Brian O'Connorb499b352015-02-03 16:46:15 -0800114 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800115
Brian O'Connor66630c82014-10-02 21:08:19 -0700116 @Activate
117 public void activate() {
118 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700119 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700120 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorbdc7f002015-02-18 20:49:41 -0800121 batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch"));
122 workerExecutor = newFixedThreadPool(NUM_THREADS, groupedThreads("onos/intent", "worker-%d"));
Brian O'Connor520c0522014-11-23 23:50:47 -0800123 idGenerator = coreService.getIdGenerator("intent-ids");
124 Intent.bindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700125 log.info("Started");
126 }
127
128 @Deactivate
129 public void deactivate() {
130 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700131 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700132 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connordb15b042015-02-04 14:59:28 -0800133 batchExecutor.shutdown();
Brian O'Connor3c58e962015-04-28 23:21:51 -0700134 workerExecutor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800135 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700136 log.info("Stopped");
137 }
138
139 @Override
140 public void submit(Intent intent) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900141 checkPermission(Permission.INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700142 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800143 IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800144 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700145 }
146
147 @Override
148 public void withdraw(Intent intent) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900149 checkPermission(Permission.INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700150 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800151 IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800152 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700153 }
154
Brian O'Connor66630c82014-10-02 21:08:19 -0700155 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700156 public void purge(Intent intent) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900157 checkPermission(Permission.INTENT_WRITE);
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700158 checkNotNull(intent, INTENT_NULL);
159 IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null);
160 store.addPending(data);
161 }
162
163 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800164 public Intent getIntent(Key key) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900165 checkPermission(Permission.INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800166 return store.getIntent(key);
167 }
168
169 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700170 public Iterable<Intent> getIntents() {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900171 checkPermission(Permission.INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700172 return store.getIntents();
173 }
174
175 @Override
Thomas Vachuskac46af202015-06-03 16:43:27 -0700176 public Iterable<IntentData> getIntentData() {
177 checkPermission(Permission.INTENT_READ);
178 return store.getIntentData(false, 0);
179 }
180
181 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700182 public long getIntentCount() {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900183 checkPermission(Permission.INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700184 return store.getIntentCount();
185 }
186
187 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800188 public IntentState getIntentState(Key intentKey) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900189 checkPermission(Permission.INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800190 checkNotNull(intentKey, INTENT_ID_NULL);
191 return store.getIntentState(intentKey);
Brian O'Connor66630c82014-10-02 21:08:19 -0700192 }
193
194 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800195 public List<Intent> getInstallableIntents(Key intentKey) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900196 checkPermission(Permission.INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800197 checkNotNull(intentKey, INTENT_ID_NULL);
198 return store.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700199 }
200
201 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800202 public boolean isLocal(Key intentKey) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900203 checkPermission(Permission.INTENT_READ);
Brian O'Connorbe28a872015-02-19 21:44:37 -0800204 return store.isMaster(intentKey);
205 }
206
207 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700208 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800209 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700210 }
211
212 @Override
213 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800214 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700215 }
216
217 @Override
218 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800219 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700220 }
221
222 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800223 public Iterable<Intent> getPending() {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900224 checkPermission(Permission.INTENT_READ);
225
Jonathan Hart34f1e382015-02-24 16:52:23 -0800226 return store.getPending();
227 }
228
Brian O'Connor66630c82014-10-02 21:08:19 -0700229 // Store delegate to re-post events emitted from the store.
230 private class InternalStoreDelegate implements IntentStoreDelegate {
231 @Override
232 public void notify(IntentEvent event) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700233 post(event);
Brian O'Connor66630c82014-10-02 21:08:19 -0700234 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800235
236 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800237 public void process(IntentData data) {
238 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800239 }
Thomas Vachuskac46af202015-06-03 16:43:27 -0700240
241 @Override
242 public void onUpdate(IntentData intentData) {
243 trackerService.trackIntent(intentData);
244 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700245 }
246
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800247 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800248 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800249 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800250 for (Key key : intentKeys) {
251 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800252 if (intent == null) {
253 continue;
254 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800255 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800256 }
257
Jonathan Hart96c5a4a2015-07-31 14:23:33 -0700258 // If required, compile all currently failed intents.
259 for (Intent intent : getIntents()) {
260 IntentState state = getIntentState(intent.key());
261 if ((compileAllFailed && RECOMPILE.contains(state))
262 || intentAllowsPartialFailure(intent)) {
263 if (WITHDRAW.contains(state)) {
264 withdraw(intent);
265 } else {
266 submit(intent);
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 SHIMIZU36a8a6e2015-02-13 15:38:45 -0800288 private Future<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);
291 return workerExecutor.submit(new IntentWorker(initial));
Sho SHIMIZU8d9d1362015-02-04 12:28:15 -0800292 }
293
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800294 private class IntentBatchProcess implements Runnable {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800295
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800296 protected final Collection<IntentData> data;
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800297
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800298 IntentBatchProcess(Collection<IntentData> data) {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800299 this.data = checkNotNull(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800300 }
301
302 @Override
303 public void run() {
304 try {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800305 /*
306 1. wrap each intentdata in a runnable and submit
307 2. wait for completion of all the work
308 3. accumulate results and submit batch write of IntentData to store
309 (we can also try to update these individually)
310 */
311 submitUpdates(waitForFutures(createIntentUpdates()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800312 } catch (Exception e) {
313 log.error("Error submitting batches:", e);
314 // FIXME incomplete Intents should be cleaned up
315 // (transition to FAILED, etc.)
316
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800317 // the batch has failed
318 // TODO: maybe we should do more?
319 log.error("Walk the plank, matey...");
Brian O'Connorb499b352015-02-03 16:46:15 -0800320 //FIXME
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800321// batchService.removeIntentOperations(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800322 }
Brian O'Connor3c4b00d2015-02-22 20:42:26 -0800323 accumulator.ready();
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800324 }
325
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800326 private List<Future<FinalIntentProcessPhase>> createIntentUpdates() {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800327 return data.stream()
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800328 .map(IntentManager.this::submitIntentData)
329 .collect(Collectors.toList());
330 }
331
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800332 private List<FinalIntentProcessPhase> waitForFutures(List<Future<FinalIntentProcessPhase>> futures) {
333 ImmutableList.Builder<FinalIntentProcessPhase> updateBuilder = ImmutableList.builder();
334 for (Future<FinalIntentProcessPhase> future : futures) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800335 try {
336 updateBuilder.add(future.get());
337 } catch (InterruptedException | ExecutionException e) {
338 //FIXME
339 log.warn("Future failed: {}", e);
340 }
341 }
342 return updateBuilder.build();
343 }
344
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800345 private void submitUpdates(List<FinalIntentProcessPhase> updates) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800346 store.batchWrite(updates.stream()
Brian O'Connorb5dcc512015-03-24 17:28:00 -0700347 .map(FinalIntentProcessPhase::data)
348 .collect(Collectors.toList()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800349 }
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800350 }
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800351
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700352 private class InternalBatchDelegate implements IntentBatchDelegate {
353 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800354 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800355 log.debug("Execute {} operation(s).", operations.size());
356 log.trace("Execute operations: {}", operations);
Sho SHIMIZU94b03b12015-04-10 14:53:13 -0700357
358 // batchExecutor is single-threaded, so only one batch is in flight at a time
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800359 batchExecutor.execute(new IntentBatchProcess(operations));
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700360 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700361 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800362
363 private class InternalIntentProcessor implements IntentProcessor {
364 @Override
365 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
366 return compilerRegistry.compile(intent, previousInstallables);
367 }
368
369 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700370 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700371 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800372 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700373 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800374
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700375 private enum Direction {
376 ADD,
377 REMOVE
378 }
379
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700380 private void applyIntentData(Optional<IntentData> intentData,
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700381 FlowRuleOperations.Builder builder,
382 Direction direction) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700383 if (!intentData.isPresent()) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700384 return;
385 }
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700386 IntentData data = intentData.get();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700387
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700388 List<Intent> intentsToApply = data.installables();
389 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
390 throw new IllegalStateException("installable intents must be FlowRuleIntent");
391 }
392
393 if (direction == Direction.ADD) {
394 trackerService.addTrackedResources(data.key(), data.intent().resources());
395 intentsToApply.forEach(installable ->
396 trackerService.addTrackedResources(data.key(), installable.resources()));
397 } else {
398 trackerService.removeTrackedResources(data.key(), data.intent().resources());
399 intentsToApply.forEach(installable ->
400 trackerService.removeTrackedResources(data.intent().key(),
401 installable.resources()));
402 }
403
404 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
405 builder.newStage();
406
407 List<Collection<FlowRule>> stages = intentsToApply.stream()
408 .map(x -> (FlowRuleIntent) x)
409 .map(FlowRuleIntent::flowRules)
410 .collect(Collectors.toList());
411
412 for (Collection<FlowRule> rules : stages) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700413 if (direction == Direction.ADD) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700414 rules.forEach(builder::add);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700415 } else {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700416 rules.forEach(builder::remove);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700417 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800418 }
419
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800420 }
421
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700422 private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800423 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800424
425 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700426 applyIntentData(toUninstall, builder, Direction.REMOVE);
427 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800428
429 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
430 @Override
431 public void onSuccess(FlowRuleOperations ops) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700432 if (toInstall.isPresent()) {
433 IntentData installData = toInstall.get();
434 log.debug("Completed installing: {}", installData.key());
435 installData.setState(INSTALLED);
436 store.write(installData);
437 } else if (toUninstall.isPresent()) {
438 IntentData uninstallData = toUninstall.get();
439 log.debug("Completed withdrawing: {}", uninstallData.key());
440 switch (uninstallData.request()) {
441 case INSTALL_REQ:
442 uninstallData.setState(FAILED);
443 break;
444 case WITHDRAW_REQ:
445 default: //TODO "default" case should not happen
446 uninstallData.setState(WITHDRAWN);
447 break;
448 }
449 store.write(uninstallData);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700450 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800451 }
452
453 @Override
454 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700455 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700456 if (toInstall.isPresent()) {
457 IntentData installData = toInstall.get();
458 log.warn("Failed installation: {} {} on {}",
459 installData.key(), installData.intent(), ops);
460 installData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700461 installData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700462 store.write(installData);
463 }
Sho SHIMIZUd4936252015-04-10 15:03:57 -0700464 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700465 if (toUninstall.isPresent()) {
466 IntentData uninstallData = toUninstall.get();
467 log.warn("Failed withdrawal: {} {} on {}",
468 uninstallData.key(), uninstallData.intent(), ops);
469 uninstallData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700470 uninstallData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700471 store.write(uninstallData);
472 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800473 }
474 });
475
Brian O'Connora7674262015-06-04 13:55:18 -0700476 if (log.isTraceEnabled()) {
477 log.trace("applying intent {} -> {} with {} rules: {}",
478 toUninstall.isPresent() ? toUninstall.get().key() : "<empty>",
479 toInstall.isPresent() ? toInstall.get().key() : "<empty>",
480 operations.stages().stream().mapToLong(i -> i.size()).sum(),
481 operations.stages());
482 }
483
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800484 flowRuleService.apply(operations);
485 }
486
Brian O'Connor66630c82014-10-02 21:08:19 -0700487}