blob: baa3bf4d33e05c7b9d12318f5e9ca3f4457cdae5 [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;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080028import org.onosproject.net.flow.FlowRule;
Brian O'Connor0e271dc2015-02-04 18:20:25 -080029import org.onosproject.net.flow.FlowRuleOperations;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080030import org.onosproject.net.flow.FlowRuleOperationsContext;
Brian O'Connorabafb502014-12-02 22:26:20 -080031import org.onosproject.net.flow.FlowRuleService;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080032import org.onosproject.net.intent.FlowRuleIntent;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.net.intent.Intent;
34import org.onosproject.net.intent.IntentBatchDelegate;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.intent.IntentCompiler;
Brian O'Connorcff03322015-02-03 15:28:59 -080036import org.onosproject.net.intent.IntentData;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.net.intent.IntentEvent;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.net.intent.IntentExtensionService;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.intent.IntentListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.net.intent.IntentService;
41import org.onosproject.net.intent.IntentState;
42import org.onosproject.net.intent.IntentStore;
Brian O'Connorabafb502014-12-02 22:26:20 -080043import org.onosproject.net.intent.IntentStoreDelegate;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080044import org.onosproject.net.intent.Key;
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -080045import org.onosproject.net.intent.impl.phase.FinalIntentProcessPhase;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080046import org.onosproject.net.intent.impl.phase.IntentProcessPhase;
Sho SHIMIZU662c3db2015-02-23 16:59:01 -080047import org.onosproject.net.intent.impl.phase.IntentWorker;
Brian O'Connor66630c82014-10-02 21:08:19 -070048import org.slf4j.Logger;
49
Brian O'Connorf0c5a052015-04-27 00:34:53 -070050import java.util.Collection;
51import java.util.EnumSet;
52import java.util.List;
53import java.util.Map;
54import java.util.Optional;
55import java.util.concurrent.ExecutionException;
56import java.util.concurrent.ExecutorService;
57import java.util.concurrent.Future;
58import java.util.stream.Collectors;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070059
Brian O'Connorfa81eae2014-10-30 13:20:05 -070060import static com.google.common.base.Preconditions.checkNotNull;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080061import static java.util.concurrent.Executors.newFixedThreadPool;
Brian O'Connordb15b042015-02-04 14:59:28 -080062import static java.util.concurrent.Executors.newSingleThreadExecutor;
Brian O'Connorbdc7f002015-02-18 20:49:41 -080063import static org.onlab.util.Tools.groupedThreads;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070064import static org.onosproject.net.intent.IntentState.*;
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070065import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
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;
Changhoon Yoonb856b812015-08-10 03:47:19 +090069import static org.onosproject.security.AppPermission.Type.*;
70
Brian O'Connor66630c82014-10-02 21:08:19 -070071
72/**
Brian O'Connorce2d8b52015-07-29 16:24:13 -070073 * An implementation of intent service.
Brian O'Connor66630c82014-10-02 21:08:19 -070074 */
75@Component(immediate = true)
76@Service
77public class IntentManager
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070078 extends AbstractListenerManager<IntentEvent, IntentListener>
Brian O'Connor66630c82014-10-02 21:08:19 -070079 implements IntentService, IntentExtensionService {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070080
Sho SHIMIZU8b5051d2014-11-05 11:24:13 -080081 private static final Logger log = getLogger(IntentManager.class);
Brian O'Connor66630c82014-10-02 21:08:19 -070082
83 public static final String INTENT_NULL = "Intent cannot be null";
Ray Milkeyf9af43c2015-02-09 16:45:48 -080084 public static final String INTENT_ID_NULL = "Intent key cannot be null";
Brian O'Connor66630c82014-10-02 21:08:19 -070085
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080086 private static final int NUM_THREADS = 12;
87
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080088 private static final EnumSet<IntentState> RECOMPILE
89 = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070090 private static final EnumSet<IntentState> WITHDRAW
91 = EnumSet.of(WITHDRAW_REQ, WITHDRAWING, WITHDRAWN);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080092
Brian O'Connor520c0522014-11-23 23:50:47 -080093 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected CoreService coreService;
Brian O'Connor66630c82014-10-02 21:08:19 -070095
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected IntentStore store;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -0700100 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -0700101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZU214ac322015-02-23 19:30:15 -0800103 protected FlowRuleService flowRuleService;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700104
Brian O'Connordb15b042015-02-04 14:59:28 -0800105 private ExecutorService batchExecutor;
106 private ExecutorService workerExecutor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800107
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800108 private final CompilerRegistry compilerRegistry = new CompilerRegistry();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800109 private final InternalIntentProcessor processor = new InternalIntentProcessor();
Brian O'Connor520c0522014-11-23 23:50:47 -0800110 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
111 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
112 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
113 private IdGenerator idGenerator;
114
Brian O'Connorb499b352015-02-03 16:46:15 -0800115 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800116
Brian O'Connor66630c82014-10-02 21:08:19 -0700117 @Activate
118 public void activate() {
119 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700120 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700121 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorbdc7f002015-02-18 20:49:41 -0800122 batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch"));
123 workerExecutor = newFixedThreadPool(NUM_THREADS, groupedThreads("onos/intent", "worker-%d"));
Brian O'Connor520c0522014-11-23 23:50:47 -0800124 idGenerator = coreService.getIdGenerator("intent-ids");
125 Intent.bindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700126 log.info("Started");
127 }
128
129 @Deactivate
130 public void deactivate() {
131 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700132 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700133 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connordb15b042015-02-04 14:59:28 -0800134 batchExecutor.shutdown();
Brian O'Connor3c58e962015-04-28 23:21:51 -0700135 workerExecutor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800136 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700137 log.info("Stopped");
138 }
139
140 @Override
141 public void submit(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900142 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700143 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800144 IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800145 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700146 }
147
148 @Override
149 public void withdraw(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900150 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700151 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800152 IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800153 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700154 }
155
Brian O'Connor66630c82014-10-02 21:08:19 -0700156 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700157 public void purge(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900158 checkPermission(INTENT_WRITE);
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700159 checkNotNull(intent, INTENT_NULL);
160 IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null);
161 store.addPending(data);
162 }
163
164 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800165 public Intent getIntent(Key key) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900166 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800167 return store.getIntent(key);
168 }
169
170 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700171 public Iterable<Intent> getIntents() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900172 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700173 return store.getIntents();
174 }
175
176 @Override
Thomas Vachuskac46af202015-06-03 16:43:27 -0700177 public Iterable<IntentData> getIntentData() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900178 checkPermission(INTENT_READ);
Thomas Vachuskac46af202015-06-03 16:43:27 -0700179 return store.getIntentData(false, 0);
180 }
181
182 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700183 public long getIntentCount() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900184 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700185 return store.getIntentCount();
186 }
187
188 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800189 public IntentState getIntentState(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900190 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800191 checkNotNull(intentKey, INTENT_ID_NULL);
192 return store.getIntentState(intentKey);
Brian O'Connor66630c82014-10-02 21:08:19 -0700193 }
194
195 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800196 public List<Intent> getInstallableIntents(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900197 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800198 checkNotNull(intentKey, INTENT_ID_NULL);
199 return store.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700200 }
201
202 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800203 public boolean isLocal(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900204 checkPermission(INTENT_READ);
Brian O'Connorbe28a872015-02-19 21:44:37 -0800205 return store.isMaster(intentKey);
206 }
207
208 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700209 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800210 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700211 }
212
213 @Override
214 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800215 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700216 }
217
218 @Override
219 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800220 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700221 }
222
223 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800224 public Iterable<Intent> getPending() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900225 checkPermission(INTENT_READ);
Changhoon Yoon541ef712015-05-23 17:18:34 +0900226
Jonathan Hart34f1e382015-02-24 16:52:23 -0800227 return store.getPending();
228 }
229
Brian O'Connor66630c82014-10-02 21:08:19 -0700230 // Store delegate to re-post events emitted from the store.
231 private class InternalStoreDelegate implements IntentStoreDelegate {
232 @Override
233 public void notify(IntentEvent event) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700234 post(event);
Brian O'Connor66630c82014-10-02 21:08:19 -0700235 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800236
237 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800238 public void process(IntentData data) {
239 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800240 }
Thomas Vachuskac46af202015-06-03 16:43:27 -0700241
242 @Override
243 public void onUpdate(IntentData intentData) {
244 trackerService.trackIntent(intentData);
245 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700246 }
247
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800248 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800249 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800250 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800251 for (Key key : intentKeys) {
252 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800253 if (intent == null) {
254 continue;
255 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800256 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800257 }
258
Jonathan Hart0cca3e82015-09-23 17:54:11 -0700259 if (compileAllFailed) {
260 // If required, compile all currently failed intents.
261 for (Intent intent : getIntents()) {
262 IntentState state = getIntentState(intent.key());
263 if (RECOMPILE.contains(state) || intentAllowsPartialFailure(intent)) {
264 if (WITHDRAW.contains(state)) {
265 withdraw(intent);
266 } else {
267 submit(intent);
268 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800269 }
270 }
271 }
272
Brian O'Connorb499b352015-02-03 16:46:15 -0800273 //FIXME
274// for (ApplicationId appId : batches.keySet()) {
275// if (batchService.isLocalLeader(appId)) {
276// execute(batches.get(appId).build());
277// }
278// }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800279 }
280
tom95329eb2014-10-06 08:40:06 -0700281 // Topology change delegate
282 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
283 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800284 public void triggerCompile(Iterable<Key> intentKeys,
tom85258ee2014-10-07 00:10:02 -0700285 boolean compileAllFailed) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800286 buildAndSubmitBatches(intentKeys, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700287 }
tom95329eb2014-10-06 08:40:06 -0700288 }
tom85258ee2014-10-07 00:10:02 -0700289
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800290 private Future<FinalIntentProcessPhase> submitIntentData(IntentData data) {
Sho SHIMIZU0cb6fe62015-02-23 16:39:57 -0800291 IntentData current = store.getIntentData(data.key());
Sho SHIMIZUce49b602015-02-23 19:15:49 -0800292 IntentProcessPhase initial = newInitialPhase(processor, data, current);
293 return workerExecutor.submit(new IntentWorker(initial));
Sho SHIMIZU8d9d1362015-02-04 12:28:15 -0800294 }
295
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800296 private class IntentBatchProcess implements Runnable {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800297
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800298 protected final Collection<IntentData> data;
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800299
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800300 IntentBatchProcess(Collection<IntentData> data) {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800301 this.data = checkNotNull(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800302 }
303
304 @Override
305 public void run() {
306 try {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800307 /*
308 1. wrap each intentdata in a runnable and submit
309 2. wait for completion of all the work
310 3. accumulate results and submit batch write of IntentData to store
311 (we can also try to update these individually)
312 */
313 submitUpdates(waitForFutures(createIntentUpdates()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800314 } catch (Exception e) {
315 log.error("Error submitting batches:", e);
316 // FIXME incomplete Intents should be cleaned up
317 // (transition to FAILED, etc.)
318
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800319 // the batch has failed
320 // TODO: maybe we should do more?
321 log.error("Walk the plank, matey...");
Brian O'Connorb499b352015-02-03 16:46:15 -0800322 //FIXME
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800323// batchService.removeIntentOperations(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800324 }
Brian O'Connor3c4b00d2015-02-22 20:42:26 -0800325 accumulator.ready();
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800326 }
327
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800328 private List<Future<FinalIntentProcessPhase>> createIntentUpdates() {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800329 return data.stream()
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800330 .map(IntentManager.this::submitIntentData)
331 .collect(Collectors.toList());
332 }
333
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800334 private List<FinalIntentProcessPhase> waitForFutures(List<Future<FinalIntentProcessPhase>> futures) {
335 ImmutableList.Builder<FinalIntentProcessPhase> updateBuilder = ImmutableList.builder();
336 for (Future<FinalIntentProcessPhase> future : futures) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800337 try {
338 updateBuilder.add(future.get());
339 } catch (InterruptedException | ExecutionException e) {
340 //FIXME
341 log.warn("Future failed: {}", e);
342 }
343 }
344 return updateBuilder.build();
345 }
346
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800347 private void submitUpdates(List<FinalIntentProcessPhase> updates) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800348 store.batchWrite(updates.stream()
Brian O'Connorb5dcc512015-03-24 17:28:00 -0700349 .map(FinalIntentProcessPhase::data)
350 .collect(Collectors.toList()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800351 }
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800352 }
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800353
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700354 private class InternalBatchDelegate implements IntentBatchDelegate {
355 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800356 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800357 log.debug("Execute {} operation(s).", operations.size());
358 log.trace("Execute operations: {}", operations);
Sho SHIMIZU94b03b12015-04-10 14:53:13 -0700359
360 // batchExecutor is single-threaded, so only one batch is in flight at a time
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800361 batchExecutor.execute(new IntentBatchProcess(operations));
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700362 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700363 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800364
365 private class InternalIntentProcessor implements IntentProcessor {
366 @Override
367 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
368 return compilerRegistry.compile(intent, previousInstallables);
369 }
370
371 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700372 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700373 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800374 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700375 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800376
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700377 private enum Direction {
378 ADD,
379 REMOVE
380 }
381
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700382 private void applyIntentData(Optional<IntentData> intentData,
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700383 FlowRuleOperations.Builder builder,
384 Direction direction) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700385 if (!intentData.isPresent()) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700386 return;
387 }
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700388 IntentData data = intentData.get();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700389
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700390 List<Intent> intentsToApply = data.installables();
391 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
392 throw new IllegalStateException("installable intents must be FlowRuleIntent");
393 }
394
395 if (direction == Direction.ADD) {
396 trackerService.addTrackedResources(data.key(), data.intent().resources());
397 intentsToApply.forEach(installable ->
398 trackerService.addTrackedResources(data.key(), installable.resources()));
399 } else {
400 trackerService.removeTrackedResources(data.key(), data.intent().resources());
401 intentsToApply.forEach(installable ->
402 trackerService.removeTrackedResources(data.intent().key(),
403 installable.resources()));
404 }
405
406 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
407 builder.newStage();
408
409 List<Collection<FlowRule>> stages = intentsToApply.stream()
410 .map(x -> (FlowRuleIntent) x)
411 .map(FlowRuleIntent::flowRules)
412 .collect(Collectors.toList());
413
414 for (Collection<FlowRule> rules : stages) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700415 if (direction == Direction.ADD) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700416 rules.forEach(builder::add);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700417 } else {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700418 rules.forEach(builder::remove);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700419 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800420 }
421
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800422 }
423
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700424 private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800425 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800426
427 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700428 applyIntentData(toUninstall, builder, Direction.REMOVE);
429 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800430
431 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
432 @Override
433 public void onSuccess(FlowRuleOperations ops) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700434 if (toInstall.isPresent()) {
435 IntentData installData = toInstall.get();
436 log.debug("Completed installing: {}", installData.key());
437 installData.setState(INSTALLED);
438 store.write(installData);
439 } else if (toUninstall.isPresent()) {
440 IntentData uninstallData = toUninstall.get();
441 log.debug("Completed withdrawing: {}", uninstallData.key());
442 switch (uninstallData.request()) {
443 case INSTALL_REQ:
444 uninstallData.setState(FAILED);
445 break;
446 case WITHDRAW_REQ:
447 default: //TODO "default" case should not happen
448 uninstallData.setState(WITHDRAWN);
449 break;
450 }
451 store.write(uninstallData);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700452 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800453 }
454
455 @Override
456 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700457 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700458 if (toInstall.isPresent()) {
459 IntentData installData = toInstall.get();
460 log.warn("Failed installation: {} {} on {}",
461 installData.key(), installData.intent(), ops);
462 installData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700463 installData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700464 store.write(installData);
465 }
Sho SHIMIZUd4936252015-04-10 15:03:57 -0700466 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700467 if (toUninstall.isPresent()) {
468 IntentData uninstallData = toUninstall.get();
469 log.warn("Failed withdrawal: {} {} on {}",
470 uninstallData.key(), uninstallData.intent(), ops);
471 uninstallData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700472 uninstallData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700473 store.write(uninstallData);
474 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800475 }
476 });
477
Brian O'Connora7674262015-06-04 13:55:18 -0700478 if (log.isTraceEnabled()) {
479 log.trace("applying intent {} -> {} with {} rules: {}",
480 toUninstall.isPresent() ? toUninstall.get().key() : "<empty>",
481 toInstall.isPresent() ? toInstall.get().key() : "<empty>",
482 operations.stages().stream().mapToLong(i -> i.size()).sum(),
483 operations.stages());
484 }
485
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800486 flowRuleService.apply(operations);
487 }
488
Brian O'Connor66630c82014-10-02 21:08:19 -0700489}