blob: 62174e03a2d78620df284dc163893217237017cc [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
185 public long getIntentCount() {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900186 checkPermission(Permission.INTENT_READ);
187
Brian O'Connor66630c82014-10-02 21:08:19 -0700188 return store.getIntentCount();
189 }
190
191 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800192 public IntentState getIntentState(Key intentKey) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900193 checkPermission(Permission.INTENT_READ);
194
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800195 checkNotNull(intentKey, INTENT_ID_NULL);
196 return store.getIntentState(intentKey);
Brian O'Connor66630c82014-10-02 21:08:19 -0700197 }
198
199 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800200 public List<Intent> getInstallableIntents(Key intentKey) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900201 checkPermission(Permission.INTENT_READ);
202
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800203 checkNotNull(intentKey, INTENT_ID_NULL);
204 return store.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700205 }
206
207 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800208 public boolean isLocal(Key intentKey) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900209 checkPermission(Permission.INTENT_READ);
210
Brian O'Connorbe28a872015-02-19 21:44:37 -0800211 return store.isMaster(intentKey);
212 }
213
214 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700215 public void addListener(IntentListener listener) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900216 checkPermission(Permission.INTENT_EVENT);
217
Brian O'Connor66630c82014-10-02 21:08:19 -0700218 listenerRegistry.addListener(listener);
219 }
220
221 @Override
222 public void removeListener(IntentListener listener) {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900223 checkPermission(Permission.INTENT_EVENT);
224
Brian O'Connor66630c82014-10-02 21:08:19 -0700225 listenerRegistry.removeListener(listener);
226 }
227
228 @Override
229 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800230 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700231 }
232
233 @Override
234 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800235 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700236 }
237
238 @Override
239 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800240 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700241 }
242
243 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800244 public Iterable<Intent> getPending() {
Changhoon Yoon541ef712015-05-23 17:18:34 +0900245 checkPermission(Permission.INTENT_READ);
246
Jonathan Hart34f1e382015-02-24 16:52:23 -0800247 return store.getPending();
248 }
249
Brian O'Connor66630c82014-10-02 21:08:19 -0700250 // Store delegate to re-post events emitted from the store.
251 private class InternalStoreDelegate implements IntentStoreDelegate {
252 @Override
253 public void notify(IntentEvent event) {
tom85258ee2014-10-07 00:10:02 -0700254 eventDispatcher.post(event);
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 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700261 }
262
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800263 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800264 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800265 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800266 for (Key key : intentKeys) {
267 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800268 if (intent == null) {
269 continue;
270 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800271 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800272 }
273
274 if (compileAllFailed) {
275 // If required, compile all currently failed intents.
276 for (Intent intent : getIntents()) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800277 IntentState state = getIntentState(intent.key());
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800278 if (RECOMPILE.contains(state)) {
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800279 if (state == WITHDRAW_REQ) {
Brian O'Connor03406a42015-02-03 17:28:57 -0800280 withdraw(intent);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800281 } else {
Brian O'Connor03406a42015-02-03 17:28:57 -0800282 submit(intent);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800283 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800284 }
285 }
286 }
287
Brian O'Connorb499b352015-02-03 16:46:15 -0800288 //FIXME
289// for (ApplicationId appId : batches.keySet()) {
290// if (batchService.isLocalLeader(appId)) {
291// execute(batches.get(appId).build());
292// }
293// }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800294 }
295
tom95329eb2014-10-06 08:40:06 -0700296 // Topology change delegate
297 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
298 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800299 public void triggerCompile(Iterable<Key> intentKeys,
tom85258ee2014-10-07 00:10:02 -0700300 boolean compileAllFailed) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800301 buildAndSubmitBatches(intentKeys, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700302 }
tom95329eb2014-10-06 08:40:06 -0700303 }
tom85258ee2014-10-07 00:10:02 -0700304
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800305 private Future<FinalIntentProcessPhase> submitIntentData(IntentData data) {
Sho SHIMIZU0cb6fe62015-02-23 16:39:57 -0800306 IntentData current = store.getIntentData(data.key());
Sho SHIMIZUce49b602015-02-23 19:15:49 -0800307 IntentProcessPhase initial = newInitialPhase(processor, data, current);
308 return workerExecutor.submit(new IntentWorker(initial));
Sho SHIMIZU8d9d1362015-02-04 12:28:15 -0800309 }
310
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800311 private class IntentBatchProcess implements Runnable {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800312
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800313 protected final Collection<IntentData> data;
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800314
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800315 IntentBatchProcess(Collection<IntentData> data) {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800316 this.data = checkNotNull(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800317 }
318
319 @Override
320 public void run() {
321 try {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800322 /*
323 1. wrap each intentdata in a runnable and submit
324 2. wait for completion of all the work
325 3. accumulate results and submit batch write of IntentData to store
326 (we can also try to update these individually)
327 */
328 submitUpdates(waitForFutures(createIntentUpdates()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800329 } catch (Exception e) {
330 log.error("Error submitting batches:", e);
331 // FIXME incomplete Intents should be cleaned up
332 // (transition to FAILED, etc.)
333
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800334 // the batch has failed
335 // TODO: maybe we should do more?
336 log.error("Walk the plank, matey...");
Brian O'Connorb499b352015-02-03 16:46:15 -0800337 //FIXME
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800338// batchService.removeIntentOperations(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800339 }
Brian O'Connor3c4b00d2015-02-22 20:42:26 -0800340 accumulator.ready();
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800341 }
342
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800343 private List<Future<FinalIntentProcessPhase>> createIntentUpdates() {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800344 return data.stream()
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800345 .map(IntentManager.this::submitIntentData)
346 .collect(Collectors.toList());
347 }
348
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800349 private List<FinalIntentProcessPhase> waitForFutures(List<Future<FinalIntentProcessPhase>> futures) {
350 ImmutableList.Builder<FinalIntentProcessPhase> updateBuilder = ImmutableList.builder();
351 for (Future<FinalIntentProcessPhase> future : futures) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800352 try {
353 updateBuilder.add(future.get());
354 } catch (InterruptedException | ExecutionException e) {
355 //FIXME
356 log.warn("Future failed: {}", e);
357 }
358 }
359 return updateBuilder.build();
360 }
361
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800362 private void submitUpdates(List<FinalIntentProcessPhase> updates) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800363 store.batchWrite(updates.stream()
Brian O'Connorb5dcc512015-03-24 17:28:00 -0700364 .map(FinalIntentProcessPhase::data)
365 .collect(Collectors.toList()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800366 }
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800367 }
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800368
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700369 private class InternalBatchDelegate implements IntentBatchDelegate {
370 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800371 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800372 log.debug("Execute {} operation(s).", operations.size());
373 log.trace("Execute operations: {}", operations);
Sho SHIMIZU94b03b12015-04-10 14:53:13 -0700374
375 // batchExecutor is single-threaded, so only one batch is in flight at a time
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800376 batchExecutor.execute(new IntentBatchProcess(operations));
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700377 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700378 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800379
380 private class InternalIntentProcessor implements IntentProcessor {
381 @Override
382 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
383 return compilerRegistry.compile(intent, previousInstallables);
384 }
385
386 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700387 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700388 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800389 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700390 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800391
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700392 private enum Direction {
393 ADD,
394 REMOVE
395 }
396
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700397 private void applyIntentData(Optional<IntentData> intentData,
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700398 FlowRuleOperations.Builder builder,
399 Direction direction) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700400 if (!intentData.isPresent()) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700401 return;
402 }
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700403 IntentData data = intentData.get();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700404
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700405 List<Intent> intentsToApply = data.installables();
406 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
407 throw new IllegalStateException("installable intents must be FlowRuleIntent");
408 }
409
410 if (direction == Direction.ADD) {
411 trackerService.addTrackedResources(data.key(), data.intent().resources());
412 intentsToApply.forEach(installable ->
413 trackerService.addTrackedResources(data.key(), installable.resources()));
414 } else {
415 trackerService.removeTrackedResources(data.key(), data.intent().resources());
416 intentsToApply.forEach(installable ->
417 trackerService.removeTrackedResources(data.intent().key(),
418 installable.resources()));
419 }
420
421 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
422 builder.newStage();
423
424 List<Collection<FlowRule>> stages = intentsToApply.stream()
425 .map(x -> (FlowRuleIntent) x)
426 .map(FlowRuleIntent::flowRules)
427 .collect(Collectors.toList());
428
429 for (Collection<FlowRule> rules : stages) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700430 if (direction == Direction.ADD) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700431 rules.forEach(builder::add);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700432 } else {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700433 rules.forEach(builder::remove);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700434 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800435 }
436
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800437 }
438
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700439 private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800440 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800441
442 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700443 applyIntentData(toUninstall, builder, Direction.REMOVE);
444 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800445
446 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
447 @Override
448 public void onSuccess(FlowRuleOperations ops) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700449 if (toInstall.isPresent()) {
450 IntentData installData = toInstall.get();
451 log.debug("Completed installing: {}", installData.key());
452 installData.setState(INSTALLED);
453 store.write(installData);
454 } else if (toUninstall.isPresent()) {
455 IntentData uninstallData = toUninstall.get();
456 log.debug("Completed withdrawing: {}", uninstallData.key());
457 switch (uninstallData.request()) {
458 case INSTALL_REQ:
459 uninstallData.setState(FAILED);
460 break;
461 case WITHDRAW_REQ:
462 default: //TODO "default" case should not happen
463 uninstallData.setState(WITHDRAWN);
464 break;
465 }
466 store.write(uninstallData);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700467 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800468 }
469
470 @Override
471 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700472 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700473 if (toInstall.isPresent()) {
474 IntentData installData = toInstall.get();
475 log.warn("Failed installation: {} {} on {}",
476 installData.key(), installData.intent(), ops);
477 installData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700478 installData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700479 store.write(installData);
480 }
Sho SHIMIZUd4936252015-04-10 15:03:57 -0700481 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700482 if (toUninstall.isPresent()) {
483 IntentData uninstallData = toUninstall.get();
484 log.warn("Failed withdrawal: {} {} on {}",
485 uninstallData.key(), uninstallData.intent(), ops);
486 uninstallData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700487 uninstallData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700488 store.write(uninstallData);
489 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800490 }
491 });
492
493 flowRuleService.apply(operations);
494 }
495
Brian O'Connor66630c82014-10-02 21:08:19 -0700496}