blob: ded39246340f2e06a26696c8714ccfc24b24742a [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.*;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080066import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
Changhoon Yoon541ef712015-05-23 17:18:34 +090067import static org.onosproject.security.AppGuard.checkPermission;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070068import static org.slf4j.LoggerFactory.getLogger;
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);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080088
Brian O'Connor520c0522014-11-23 23:50:47 -080089 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected CoreService coreService;
Brian O'Connor66630c82014-10-02 21:08:19 -070091
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected IntentStore store;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -070096 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -070097
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZU214ac322015-02-23 19:30:15 -080099 protected FlowRuleService flowRuleService;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700100
Brian O'Connordb15b042015-02-04 14:59:28 -0800101 private ExecutorService batchExecutor;
102 private ExecutorService workerExecutor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800103
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800104 private final CompilerRegistry compilerRegistry = new CompilerRegistry();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800105 private final InternalIntentProcessor processor = new InternalIntentProcessor();
Brian O'Connor520c0522014-11-23 23:50:47 -0800106 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
107 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
108 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
109 private IdGenerator idGenerator;
110
Brian O'Connorb499b352015-02-03 16:46:15 -0800111 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800112
Brian O'Connor66630c82014-10-02 21:08:19 -0700113 @Activate
114 public void activate() {
115 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700116 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700117 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorbdc7f002015-02-18 20:49:41 -0800118 batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch"));
119 workerExecutor = newFixedThreadPool(NUM_THREADS, groupedThreads("onos/intent", "worker-%d"));
Brian O'Connor520c0522014-11-23 23:50:47 -0800120 idGenerator = coreService.getIdGenerator("intent-ids");
121 Intent.bindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700122 log.info("Started");
123 }
124
125 @Deactivate
126 public void deactivate() {
127 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700128 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700129 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connordb15b042015-02-04 14:59:28 -0800130 batchExecutor.shutdown();
Brian O'Connor3c58e962015-04-28 23:21:51 -0700131 workerExecutor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800132 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700133 log.info("Stopped");
134 }
135
136 @Override
137 public void submit(Intent intent) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900138 checkPermission(Permission.INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700139 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800140 IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800141 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700142 }
143
144 @Override
145 public void withdraw(Intent intent) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900146 checkPermission(Permission.INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700147 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800148 IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800149 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700150 }
151
Brian O'Connor66630c82014-10-02 21:08:19 -0700152 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700153 public void purge(Intent intent) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900154 checkPermission(Permission.INTENT_WRITE);
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700155 checkNotNull(intent, INTENT_NULL);
156 IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null);
157 store.addPending(data);
158 }
159
160 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800161 public Intent getIntent(Key key) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900162 checkPermission(Permission.INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800163 return store.getIntent(key);
164 }
165
166 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700167 public Iterable<Intent> getIntents() {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900168 checkPermission(Permission.INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700169 return store.getIntents();
170 }
171
172 @Override
Thomas Vachuskac46af202015-06-03 16:43:27 -0700173 public Iterable<IntentData> getIntentData() {
174 checkPermission(Permission.INTENT_READ);
175 return store.getIntentData(false, 0);
176 }
177
178 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700179 public long getIntentCount() {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900180 checkPermission(Permission.INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700181 return store.getIntentCount();
182 }
183
184 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800185 public IntentState getIntentState(Key intentKey) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900186 checkPermission(Permission.INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800187 checkNotNull(intentKey, INTENT_ID_NULL);
188 return store.getIntentState(intentKey);
Brian O'Connor66630c82014-10-02 21:08:19 -0700189 }
190
191 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800192 public List<Intent> getInstallableIntents(Key intentKey) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900193 checkPermission(Permission.INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800194 checkNotNull(intentKey, INTENT_ID_NULL);
195 return store.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700196 }
197
198 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800199 public boolean isLocal(Key intentKey) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900200 checkPermission(Permission.INTENT_READ);
Brian O'Connorbe28a872015-02-19 21:44:37 -0800201 return store.isMaster(intentKey);
202 }
203
204 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700205 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800206 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700207 }
208
209 @Override
210 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800211 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700212 }
213
214 @Override
215 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800216 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700217 }
218
219 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800220 public Iterable<Intent> getPending() {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900221 checkPermission(Permission.INTENT_READ);
222
Jonathan Hart34f1e382015-02-24 16:52:23 -0800223 return store.getPending();
224 }
225
Brian O'Connor66630c82014-10-02 21:08:19 -0700226 // Store delegate to re-post events emitted from the store.
227 private class InternalStoreDelegate implements IntentStoreDelegate {
228 @Override
229 public void notify(IntentEvent event) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700230 post(event);
Brian O'Connor66630c82014-10-02 21:08:19 -0700231 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800232
233 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800234 public void process(IntentData data) {
235 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800236 }
Thomas Vachuskac46af202015-06-03 16:43:27 -0700237
238 @Override
239 public void onUpdate(IntentData intentData) {
240 trackerService.trackIntent(intentData);
241 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700242 }
243
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800244 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800245 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800246 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800247 for (Key key : intentKeys) {
248 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800249 if (intent == null) {
250 continue;
251 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800252 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800253 }
254
255 if (compileAllFailed) {
256 // If required, compile all currently failed intents.
257 for (Intent intent : getIntents()) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800258 IntentState state = getIntentState(intent.key());
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800259 if (RECOMPILE.contains(state)) {
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800260 if (state == WITHDRAW_REQ) {
Brian O'Connor03406a42015-02-03 17:28:57 -0800261 withdraw(intent);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800262 } else {
Brian O'Connor03406a42015-02-03 17:28:57 -0800263 submit(intent);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800264 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800265 }
266 }
267 }
268
Brian O'Connorb499b352015-02-03 16:46:15 -0800269 //FIXME
270// for (ApplicationId appId : batches.keySet()) {
271// if (batchService.isLocalLeader(appId)) {
272// execute(batches.get(appId).build());
273// }
274// }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800275 }
276
tom95329eb2014-10-06 08:40:06 -0700277 // Topology change delegate
278 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
279 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800280 public void triggerCompile(Iterable<Key> intentKeys,
tom85258ee2014-10-07 00:10:02 -0700281 boolean compileAllFailed) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800282 buildAndSubmitBatches(intentKeys, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700283 }
tom95329eb2014-10-06 08:40:06 -0700284 }
tom85258ee2014-10-07 00:10:02 -0700285
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800286 private Future<FinalIntentProcessPhase> submitIntentData(IntentData data) {
Sho SHIMIZU0cb6fe62015-02-23 16:39:57 -0800287 IntentData current = store.getIntentData(data.key());
Sho SHIMIZUce49b602015-02-23 19:15:49 -0800288 IntentProcessPhase initial = newInitialPhase(processor, data, current);
289 return workerExecutor.submit(new IntentWorker(initial));
Sho SHIMIZU8d9d1362015-02-04 12:28:15 -0800290 }
291
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800292 private class IntentBatchProcess implements Runnable {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800293
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800294 protected final Collection<IntentData> data;
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800295
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800296 IntentBatchProcess(Collection<IntentData> data) {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800297 this.data = checkNotNull(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800298 }
299
300 @Override
301 public void run() {
302 try {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800303 /*
304 1. wrap each intentdata in a runnable and submit
305 2. wait for completion of all the work
306 3. accumulate results and submit batch write of IntentData to store
307 (we can also try to update these individually)
308 */
309 submitUpdates(waitForFutures(createIntentUpdates()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800310 } catch (Exception e) {
311 log.error("Error submitting batches:", e);
312 // FIXME incomplete Intents should be cleaned up
313 // (transition to FAILED, etc.)
314
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800315 // the batch has failed
316 // TODO: maybe we should do more?
317 log.error("Walk the plank, matey...");
Brian O'Connorb499b352015-02-03 16:46:15 -0800318 //FIXME
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800319// batchService.removeIntentOperations(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800320 }
Brian O'Connor3c4b00d2015-02-22 20:42:26 -0800321 accumulator.ready();
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800322 }
323
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800324 private List<Future<FinalIntentProcessPhase>> createIntentUpdates() {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800325 return data.stream()
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800326 .map(IntentManager.this::submitIntentData)
327 .collect(Collectors.toList());
328 }
329
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800330 private List<FinalIntentProcessPhase> waitForFutures(List<Future<FinalIntentProcessPhase>> futures) {
331 ImmutableList.Builder<FinalIntentProcessPhase> updateBuilder = ImmutableList.builder();
332 for (Future<FinalIntentProcessPhase> future : futures) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800333 try {
334 updateBuilder.add(future.get());
335 } catch (InterruptedException | ExecutionException e) {
336 //FIXME
337 log.warn("Future failed: {}", e);
338 }
339 }
340 return updateBuilder.build();
341 }
342
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800343 private void submitUpdates(List<FinalIntentProcessPhase> updates) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800344 store.batchWrite(updates.stream()
Brian O'Connorb5dcc512015-03-24 17:28:00 -0700345 .map(FinalIntentProcessPhase::data)
346 .collect(Collectors.toList()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800347 }
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800348 }
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800349
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700350 private class InternalBatchDelegate implements IntentBatchDelegate {
351 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800352 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800353 log.debug("Execute {} operation(s).", operations.size());
354 log.trace("Execute operations: {}", operations);
Sho SHIMIZU94b03b12015-04-10 14:53:13 -0700355
356 // batchExecutor is single-threaded, so only one batch is in flight at a time
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800357 batchExecutor.execute(new IntentBatchProcess(operations));
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700358 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700359 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800360
361 private class InternalIntentProcessor implements IntentProcessor {
362 @Override
363 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
364 return compilerRegistry.compile(intent, previousInstallables);
365 }
366
367 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700368 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700369 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800370 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700371 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800372
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700373 private enum Direction {
374 ADD,
375 REMOVE
376 }
377
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700378 private void applyIntentData(Optional<IntentData> intentData,
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700379 FlowRuleOperations.Builder builder,
380 Direction direction) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700381 if (!intentData.isPresent()) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700382 return;
383 }
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700384 IntentData data = intentData.get();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700385
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700386 List<Intent> intentsToApply = data.installables();
387 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
388 throw new IllegalStateException("installable intents must be FlowRuleIntent");
389 }
390
391 if (direction == Direction.ADD) {
392 trackerService.addTrackedResources(data.key(), data.intent().resources());
393 intentsToApply.forEach(installable ->
394 trackerService.addTrackedResources(data.key(), installable.resources()));
395 } else {
396 trackerService.removeTrackedResources(data.key(), data.intent().resources());
397 intentsToApply.forEach(installable ->
398 trackerService.removeTrackedResources(data.intent().key(),
399 installable.resources()));
400 }
401
402 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
403 builder.newStage();
404
405 List<Collection<FlowRule>> stages = intentsToApply.stream()
406 .map(x -> (FlowRuleIntent) x)
407 .map(FlowRuleIntent::flowRules)
408 .collect(Collectors.toList());
409
410 for (Collection<FlowRule> rules : stages) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700411 if (direction == Direction.ADD) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700412 rules.forEach(builder::add);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700413 } else {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700414 rules.forEach(builder::remove);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700415 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800416 }
417
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800418 }
419
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700420 private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800421 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800422
423 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700424 applyIntentData(toUninstall, builder, Direction.REMOVE);
425 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800426
427 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
428 @Override
429 public void onSuccess(FlowRuleOperations ops) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700430 if (toInstall.isPresent()) {
431 IntentData installData = toInstall.get();
432 log.debug("Completed installing: {}", installData.key());
433 installData.setState(INSTALLED);
434 store.write(installData);
435 } else if (toUninstall.isPresent()) {
436 IntentData uninstallData = toUninstall.get();
437 log.debug("Completed withdrawing: {}", uninstallData.key());
438 switch (uninstallData.request()) {
439 case INSTALL_REQ:
440 uninstallData.setState(FAILED);
441 break;
442 case WITHDRAW_REQ:
443 default: //TODO "default" case should not happen
444 uninstallData.setState(WITHDRAWN);
445 break;
446 }
447 store.write(uninstallData);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700448 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800449 }
450
451 @Override
452 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700453 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700454 if (toInstall.isPresent()) {
455 IntentData installData = toInstall.get();
456 log.warn("Failed installation: {} {} on {}",
457 installData.key(), installData.intent(), ops);
458 installData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700459 installData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700460 store.write(installData);
461 }
Sho SHIMIZUd4936252015-04-10 15:03:57 -0700462 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700463 if (toUninstall.isPresent()) {
464 IntentData uninstallData = toUninstall.get();
465 log.warn("Failed withdrawal: {} {} on {}",
466 uninstallData.key(), uninstallData.intent(), ops);
467 uninstallData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700468 uninstallData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700469 store.write(uninstallData);
470 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800471 }
472 });
473
Brian O'Connora7674262015-06-04 13:55:18 -0700474 if (log.isTraceEnabled()) {
475 log.trace("applying intent {} -> {} with {} rules: {}",
476 toUninstall.isPresent() ? toUninstall.get().key() : "<empty>",
477 toInstall.isPresent() ? toInstall.get().key() : "<empty>",
478 operations.stages().stream().mapToLong(i -> i.size()).sum(),
479 operations.stages());
480 }
481
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800482 flowRuleService.apply(operations);
483 }
484
Brian O'Connor66630c82014-10-02 21:08:19 -0700485}