blob: 16404e3fcf52d4db8e43308df52707f9e54eb8f0 [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;
Brian O'Connorabafb502014-12-02 22:26:20 -080025import org.onosproject.core.CoreService;
26import org.onosproject.core.IdGenerator;
Changhoon Yoon541ef712015-05-23 17:18:34 +090027import org.onosproject.core.Permission;
Simon Huntff663742015-05-14 13:33:05 -070028import org.onosproject.event.ListenerRegistry;
Brian O'Connorabafb502014-12-02 22:26:20 -080029import org.onosproject.event.EventDeliveryService;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080030import org.onosproject.net.flow.FlowRule;
Brian O'Connor0e271dc2015-02-04 18:20:25 -080031import org.onosproject.net.flow.FlowRuleOperations;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080032import org.onosproject.net.flow.FlowRuleOperationsContext;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.net.flow.FlowRuleService;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080034import org.onosproject.net.intent.FlowRuleIntent;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.intent.Intent;
36import org.onosproject.net.intent.IntentBatchDelegate;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.net.intent.IntentCompiler;
Brian O'Connorcff03322015-02-03 15:28:59 -080038import org.onosproject.net.intent.IntentData;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.intent.IntentEvent;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.net.intent.IntentExtensionService;
Brian O'Connorabafb502014-12-02 22:26:20 -080041import org.onosproject.net.intent.IntentListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.net.intent.IntentService;
43import org.onosproject.net.intent.IntentState;
44import org.onosproject.net.intent.IntentStore;
Brian O'Connorabafb502014-12-02 22:26:20 -080045import org.onosproject.net.intent.IntentStoreDelegate;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080046import org.onosproject.net.intent.Key;
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -080047import org.onosproject.net.intent.impl.phase.FinalIntentProcessPhase;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080048import org.onosproject.net.intent.impl.phase.IntentProcessPhase;
Sho SHIMIZU662c3db2015-02-23 16:59:01 -080049import org.onosproject.net.intent.impl.phase.IntentWorker;
Brian O'Connor66630c82014-10-02 21:08:19 -070050import org.slf4j.Logger;
51
Brian O'Connorf0c5a052015-04-27 00:34:53 -070052import java.util.Collection;
53import java.util.EnumSet;
54import java.util.List;
55import java.util.Map;
56import java.util.Optional;
57import java.util.concurrent.ExecutionException;
58import java.util.concurrent.ExecutorService;
59import java.util.concurrent.Future;
60import java.util.stream.Collectors;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070061
Brian O'Connorfa81eae2014-10-30 13:20:05 -070062import static com.google.common.base.Preconditions.checkNotNull;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080063import static java.util.concurrent.Executors.newFixedThreadPool;
Brian O'Connordb15b042015-02-04 14:59:28 -080064import static java.util.concurrent.Executors.newSingleThreadExecutor;
Brian O'Connorbdc7f002015-02-18 20:49:41 -080065import static org.onlab.util.Tools.groupedThreads;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070066import static org.onosproject.net.intent.IntentState.*;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080067import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070068import static org.slf4j.LoggerFactory.getLogger;
Changhoon Yoon541ef712015-05-23 17:18:34 +090069import static org.onosproject.security.AppGuard.checkPermission;
70
Brian O'Connor66630c82014-10-02 21:08:19 -070071
72/**
73 * An implementation of Intent Manager.
74 */
75@Component(immediate = true)
76@Service
77public class IntentManager
78 implements IntentService, IntentExtensionService {
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
Simon Huntff663742015-05-14 13:33:05 -070089 private final ListenerRegistry<IntentEvent, IntentListener>
90 listenerRegistry = new ListenerRegistry<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070091
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)
Brian O'Connor66630c82014-10-02 21:08:19 -0700102 protected EventDeliveryService eventDispatcher;
103
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZU214ac322015-02-23 19:30:15 -0800105 protected FlowRuleService flowRuleService;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700106
Brian O'Connor520c0522014-11-23 23:50:47 -0800107
Brian O'Connordb15b042015-02-04 14:59:28 -0800108 private ExecutorService batchExecutor;
109 private ExecutorService workerExecutor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800110
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800111 private final CompilerRegistry compilerRegistry = new CompilerRegistry();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800112 private final InternalIntentProcessor processor = new InternalIntentProcessor();
Brian O'Connor520c0522014-11-23 23:50:47 -0800113 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
114 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
115 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
116 private IdGenerator idGenerator;
117
Brian O'Connorb499b352015-02-03 16:46:15 -0800118 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800119
Brian O'Connor66630c82014-10-02 21:08:19 -0700120 @Activate
121 public void activate() {
122 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700123 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700124 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorbdc7f002015-02-18 20:49:41 -0800125 batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch"));
126 workerExecutor = newFixedThreadPool(NUM_THREADS, groupedThreads("onos/intent", "worker-%d"));
Brian O'Connor520c0522014-11-23 23:50:47 -0800127 idGenerator = coreService.getIdGenerator("intent-ids");
128 Intent.bindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700129 log.info("Started");
130 }
131
132 @Deactivate
133 public void deactivate() {
134 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700135 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700136 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connordb15b042015-02-04 14:59:28 -0800137 batchExecutor.shutdown();
Brian O'Connor3c58e962015-04-28 23:21:51 -0700138 workerExecutor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800139 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700140 log.info("Stopped");
141 }
142
143 @Override
144 public void submit(Intent intent) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900145 checkPermission(Permission.INTENT_WRITE);
146
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.INSTALL_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800149 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700150 }
151
152 @Override
153 public void withdraw(Intent intent) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900154 checkPermission(Permission.INTENT_WRITE);
155
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 Yoon541ef712015-05-23 17:18:34 +0900163 checkPermission(Permission.INTENT_WRITE);
164
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700165 checkNotNull(intent, INTENT_NULL);
166 IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null);
167 store.addPending(data);
168 }
169
170 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800171 public Intent getIntent(Key key) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900172 checkPermission(Permission.INTENT_READ);
173
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800174 return store.getIntent(key);
175 }
176
177 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700178 public Iterable<Intent> getIntents() {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900179 checkPermission(Permission.INTENT_READ);
180
Brian O'Connor66630c82014-10-02 21:08:19 -0700181 return store.getIntents();
182 }
183
184 @Override
Thomas Vachuskac46af202015-06-03 16:43:27 -0700185 public Iterable<IntentData> getIntentData() {
186 checkPermission(Permission.INTENT_READ);
187 return store.getIntentData(false, 0);
188 }
189
190 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700191 public long getIntentCount() {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900192 checkPermission(Permission.INTENT_READ);
193
Brian O'Connor66630c82014-10-02 21:08:19 -0700194 return store.getIntentCount();
195 }
196
197 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800198 public IntentState getIntentState(Key intentKey) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900199 checkPermission(Permission.INTENT_READ);
200
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 Yoon541ef712015-05-23 17:18:34 +0900207 checkPermission(Permission.INTENT_READ);
208
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800209 checkNotNull(intentKey, INTENT_ID_NULL);
210 return store.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700211 }
212
213 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800214 public boolean isLocal(Key intentKey) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900215 checkPermission(Permission.INTENT_READ);
216
Brian O'Connorbe28a872015-02-19 21:44:37 -0800217 return store.isMaster(intentKey);
218 }
219
220 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700221 public void addListener(IntentListener listener) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900222 checkPermission(Permission.INTENT_EVENT);
223
Brian O'Connor66630c82014-10-02 21:08:19 -0700224 listenerRegistry.addListener(listener);
225 }
226
227 @Override
228 public void removeListener(IntentListener listener) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900229 checkPermission(Permission.INTENT_EVENT);
230
Brian O'Connor66630c82014-10-02 21:08:19 -0700231 listenerRegistry.removeListener(listener);
232 }
233
234 @Override
235 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800236 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700237 }
238
239 @Override
240 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800241 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700242 }
243
244 @Override
245 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800246 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700247 }
248
249 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800250 public Iterable<Intent> getPending() {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900251 checkPermission(Permission.INTENT_READ);
252
Jonathan Hart34f1e382015-02-24 16:52:23 -0800253 return store.getPending();
254 }
255
Brian O'Connor66630c82014-10-02 21:08:19 -0700256 // Store delegate to re-post events emitted from the store.
257 private class InternalStoreDelegate implements IntentStoreDelegate {
258 @Override
259 public void notify(IntentEvent event) {
tom85258ee2014-10-07 00:10:02 -0700260 eventDispatcher.post(event);
Brian O'Connor66630c82014-10-02 21:08:19 -0700261 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800262
263 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800264 public void process(IntentData data) {
265 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800266 }
Thomas Vachuskac46af202015-06-03 16:43:27 -0700267
268 @Override
269 public void onUpdate(IntentData intentData) {
270 trackerService.trackIntent(intentData);
271 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700272 }
273
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800274 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800275 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800276 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800277 for (Key key : intentKeys) {
278 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800279 if (intent == null) {
280 continue;
281 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800282 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800283 }
284
285 if (compileAllFailed) {
286 // If required, compile all currently failed intents.
287 for (Intent intent : getIntents()) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800288 IntentState state = getIntentState(intent.key());
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800289 if (RECOMPILE.contains(state)) {
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800290 if (state == WITHDRAW_REQ) {
Brian O'Connor03406a42015-02-03 17:28:57 -0800291 withdraw(intent);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800292 } else {
Brian O'Connor03406a42015-02-03 17:28:57 -0800293 submit(intent);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800294 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800295 }
296 }
297 }
298
Brian O'Connorb499b352015-02-03 16:46:15 -0800299 //FIXME
300// for (ApplicationId appId : batches.keySet()) {
301// if (batchService.isLocalLeader(appId)) {
302// execute(batches.get(appId).build());
303// }
304// }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800305 }
306
tom95329eb2014-10-06 08:40:06 -0700307 // Topology change delegate
308 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
309 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800310 public void triggerCompile(Iterable<Key> intentKeys,
tom85258ee2014-10-07 00:10:02 -0700311 boolean compileAllFailed) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800312 buildAndSubmitBatches(intentKeys, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700313 }
tom95329eb2014-10-06 08:40:06 -0700314 }
tom85258ee2014-10-07 00:10:02 -0700315
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800316 private Future<FinalIntentProcessPhase> submitIntentData(IntentData data) {
Sho SHIMIZU0cb6fe62015-02-23 16:39:57 -0800317 IntentData current = store.getIntentData(data.key());
Sho SHIMIZUce49b602015-02-23 19:15:49 -0800318 IntentProcessPhase initial = newInitialPhase(processor, data, current);
319 return workerExecutor.submit(new IntentWorker(initial));
Sho SHIMIZU8d9d1362015-02-04 12:28:15 -0800320 }
321
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800322 private class IntentBatchProcess implements Runnable {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800323
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800324 protected final Collection<IntentData> data;
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800325
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800326 IntentBatchProcess(Collection<IntentData> data) {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800327 this.data = checkNotNull(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800328 }
329
330 @Override
331 public void run() {
332 try {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800333 /*
334 1. wrap each intentdata in a runnable and submit
335 2. wait for completion of all the work
336 3. accumulate results and submit batch write of IntentData to store
337 (we can also try to update these individually)
338 */
339 submitUpdates(waitForFutures(createIntentUpdates()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800340 } catch (Exception e) {
341 log.error("Error submitting batches:", e);
342 // FIXME incomplete Intents should be cleaned up
343 // (transition to FAILED, etc.)
344
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800345 // the batch has failed
346 // TODO: maybe we should do more?
347 log.error("Walk the plank, matey...");
Brian O'Connorb499b352015-02-03 16:46:15 -0800348 //FIXME
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800349// batchService.removeIntentOperations(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800350 }
Brian O'Connor3c4b00d2015-02-22 20:42:26 -0800351 accumulator.ready();
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800352 }
353
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800354 private List<Future<FinalIntentProcessPhase>> createIntentUpdates() {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800355 return data.stream()
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800356 .map(IntentManager.this::submitIntentData)
357 .collect(Collectors.toList());
358 }
359
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800360 private List<FinalIntentProcessPhase> waitForFutures(List<Future<FinalIntentProcessPhase>> futures) {
361 ImmutableList.Builder<FinalIntentProcessPhase> updateBuilder = ImmutableList.builder();
362 for (Future<FinalIntentProcessPhase> future : futures) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800363 try {
364 updateBuilder.add(future.get());
365 } catch (InterruptedException | ExecutionException e) {
366 //FIXME
367 log.warn("Future failed: {}", e);
368 }
369 }
370 return updateBuilder.build();
371 }
372
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800373 private void submitUpdates(List<FinalIntentProcessPhase> updates) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800374 store.batchWrite(updates.stream()
Brian O'Connorb5dcc512015-03-24 17:28:00 -0700375 .map(FinalIntentProcessPhase::data)
376 .collect(Collectors.toList()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800377 }
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800378 }
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800379
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700380 private class InternalBatchDelegate implements IntentBatchDelegate {
381 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800382 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800383 log.debug("Execute {} operation(s).", operations.size());
384 log.trace("Execute operations: {}", operations);
Sho SHIMIZU94b03b12015-04-10 14:53:13 -0700385
386 // batchExecutor is single-threaded, so only one batch is in flight at a time
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800387 batchExecutor.execute(new IntentBatchProcess(operations));
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700388 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700389 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800390
391 private class InternalIntentProcessor implements IntentProcessor {
392 @Override
393 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
394 return compilerRegistry.compile(intent, previousInstallables);
395 }
396
397 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700398 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700399 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800400 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700401 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800402
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700403 private enum Direction {
404 ADD,
405 REMOVE
406 }
407
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700408 private void applyIntentData(Optional<IntentData> intentData,
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700409 FlowRuleOperations.Builder builder,
410 Direction direction) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700411 if (!intentData.isPresent()) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700412 return;
413 }
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700414 IntentData data = intentData.get();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700415
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700416 List<Intent> intentsToApply = data.installables();
417 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
418 throw new IllegalStateException("installable intents must be FlowRuleIntent");
419 }
420
421 if (direction == Direction.ADD) {
422 trackerService.addTrackedResources(data.key(), data.intent().resources());
423 intentsToApply.forEach(installable ->
424 trackerService.addTrackedResources(data.key(), installable.resources()));
425 } else {
426 trackerService.removeTrackedResources(data.key(), data.intent().resources());
427 intentsToApply.forEach(installable ->
428 trackerService.removeTrackedResources(data.intent().key(),
429 installable.resources()));
430 }
431
432 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
433 builder.newStage();
434
435 List<Collection<FlowRule>> stages = intentsToApply.stream()
436 .map(x -> (FlowRuleIntent) x)
437 .map(FlowRuleIntent::flowRules)
438 .collect(Collectors.toList());
439
440 for (Collection<FlowRule> rules : stages) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700441 if (direction == Direction.ADD) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700442 rules.forEach(builder::add);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700443 } else {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700444 rules.forEach(builder::remove);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700445 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800446 }
447
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800448 }
449
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700450 private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800451 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800452
453 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700454 applyIntentData(toUninstall, builder, Direction.REMOVE);
455 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800456
457 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
458 @Override
459 public void onSuccess(FlowRuleOperations ops) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700460 if (toInstall.isPresent()) {
461 IntentData installData = toInstall.get();
462 log.debug("Completed installing: {}", installData.key());
463 installData.setState(INSTALLED);
464 store.write(installData);
465 } else if (toUninstall.isPresent()) {
466 IntentData uninstallData = toUninstall.get();
467 log.debug("Completed withdrawing: {}", uninstallData.key());
468 switch (uninstallData.request()) {
469 case INSTALL_REQ:
470 uninstallData.setState(FAILED);
471 break;
472 case WITHDRAW_REQ:
473 default: //TODO "default" case should not happen
474 uninstallData.setState(WITHDRAWN);
475 break;
476 }
477 store.write(uninstallData);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700478 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800479 }
480
481 @Override
482 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700483 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700484 if (toInstall.isPresent()) {
485 IntentData installData = toInstall.get();
486 log.warn("Failed installation: {} {} on {}",
487 installData.key(), installData.intent(), ops);
488 installData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700489 installData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700490 store.write(installData);
491 }
Sho SHIMIZUd4936252015-04-10 15:03:57 -0700492 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700493 if (toUninstall.isPresent()) {
494 IntentData uninstallData = toUninstall.get();
495 log.warn("Failed withdrawal: {} {} on {}",
496 uninstallData.key(), uninstallData.intent(), ops);
497 uninstallData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700498 uninstallData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700499 store.write(uninstallData);
500 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800501 }
502 });
503
Brian O'Connora7674262015-06-04 13:55:18 -0700504 if (log.isTraceEnabled()) {
505 log.trace("applying intent {} -> {} with {} rules: {}",
506 toUninstall.isPresent() ? toUninstall.get().key() : "<empty>",
507 toInstall.isPresent() ? toInstall.get().key() : "<empty>",
508 operations.stages().stream().mapToLong(i -> i.size()).sum(),
509 operations.stages());
510 }
511
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800512 flowRuleService.apply(operations);
513 }
514
Brian O'Connor66630c82014-10-02 21:08:19 -0700515}