blob: 01a167b817a498f08e9b1e8cdecd25193f987385 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Sho SHIMIZU89925242016-01-13 14:20:34 -08002 * Copyright 2014-2016 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;
Brian O'Connor66630c82014-10-02 21:08:19 -070047import org.slf4j.Logger;
48
Brian O'Connorf0c5a052015-04-27 00:34:53 -070049import java.util.Collection;
50import java.util.EnumSet;
51import java.util.List;
52import java.util.Map;
53import java.util.Optional;
54import java.util.concurrent.ExecutionException;
55import java.util.concurrent.ExecutorService;
56import java.util.concurrent.Future;
57import java.util.stream.Collectors;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070058
Brian O'Connorfa81eae2014-10-30 13:20:05 -070059import static com.google.common.base.Preconditions.checkNotNull;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080060import static java.util.concurrent.Executors.newFixedThreadPool;
Brian O'Connordb15b042015-02-04 14:59:28 -080061import static java.util.concurrent.Executors.newSingleThreadExecutor;
Brian O'Connorbdc7f002015-02-18 20:49:41 -080062import static org.onlab.util.Tools.groupedThreads;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070063import static org.onosproject.net.intent.IntentState.*;
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070064import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080065import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
Changhoon Yoon541ef712015-05-23 17:18:34 +090066import static org.onosproject.security.AppGuard.checkPermission;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070067import static org.slf4j.LoggerFactory.getLogger;
Changhoon Yoonb856b812015-08-10 03:47:19 +090068import static org.onosproject.security.AppPermission.Type.*;
69
Brian O'Connor66630c82014-10-02 21:08:19 -070070
71/**
Brian O'Connorce2d8b52015-07-29 16:24:13 -070072 * An implementation of intent service.
Brian O'Connor66630c82014-10-02 21:08:19 -070073 */
74@Component(immediate = true)
75@Service
76public class IntentManager
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070077 extends AbstractListenerManager<IntentEvent, IntentListener>
Brian O'Connor66630c82014-10-02 21:08:19 -070078 implements IntentService, IntentExtensionService {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070079
Sho SHIMIZU8b5051d2014-11-05 11:24:13 -080080 private static final Logger log = getLogger(IntentManager.class);
Brian O'Connor66630c82014-10-02 21:08:19 -070081
82 public static final String INTENT_NULL = "Intent cannot be null";
Ray Milkeyf9af43c2015-02-09 16:45:48 -080083 public static final String INTENT_ID_NULL = "Intent key cannot be null";
Brian O'Connor66630c82014-10-02 21:08:19 -070084
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080085 private static final int NUM_THREADS = 12;
86
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080087 private static final EnumSet<IntentState> RECOMPILE
88 = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070089 private static final EnumSet<IntentState> WITHDRAW
90 = EnumSet.of(WITHDRAW_REQ, WITHDRAWING, WITHDRAWN);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080091
Brian O'Connor520c0522014-11-23 23:50:47 -080092 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected CoreService coreService;
Brian O'Connor66630c82014-10-02 21:08:19 -070094
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected IntentStore store;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -070099 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -0700100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZU214ac322015-02-23 19:30:15 -0800102 protected FlowRuleService flowRuleService;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700103
Brian O'Connordb15b042015-02-04 14:59:28 -0800104 private ExecutorService batchExecutor;
105 private ExecutorService workerExecutor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800106
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800107 private final CompilerRegistry compilerRegistry = new CompilerRegistry();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800108 private final InternalIntentProcessor processor = new InternalIntentProcessor();
Brian O'Connor520c0522014-11-23 23:50:47 -0800109 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
110 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
111 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
112 private IdGenerator idGenerator;
113
Brian O'Connorb499b352015-02-03 16:46:15 -0800114 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800115
Brian O'Connor66630c82014-10-02 21:08:19 -0700116 @Activate
117 public void activate() {
118 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700119 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700120 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorbdc7f002015-02-18 20:49:41 -0800121 batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch"));
122 workerExecutor = newFixedThreadPool(NUM_THREADS, groupedThreads("onos/intent", "worker-%d"));
Brian O'Connor520c0522014-11-23 23:50:47 -0800123 idGenerator = coreService.getIdGenerator("intent-ids");
124 Intent.bindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700125 log.info("Started");
126 }
127
128 @Deactivate
129 public void deactivate() {
130 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700131 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700132 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connordb15b042015-02-04 14:59:28 -0800133 batchExecutor.shutdown();
Brian O'Connor3c58e962015-04-28 23:21:51 -0700134 workerExecutor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800135 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700136 log.info("Stopped");
137 }
138
139 @Override
140 public void submit(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900141 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700142 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800143 IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800144 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700145 }
146
147 @Override
148 public void withdraw(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900149 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700150 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800151 IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800152 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700153 }
154
Brian O'Connor66630c82014-10-02 21:08:19 -0700155 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700156 public void purge(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900157 checkPermission(INTENT_WRITE);
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700158 checkNotNull(intent, INTENT_NULL);
159 IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null);
160 store.addPending(data);
161 }
162
163 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800164 public Intent getIntent(Key key) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900165 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800166 return store.getIntent(key);
167 }
168
169 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700170 public Iterable<Intent> getIntents() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900171 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700172 return store.getIntents();
173 }
174
175 @Override
Thomas Vachuskac46af202015-06-03 16:43:27 -0700176 public Iterable<IntentData> getIntentData() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900177 checkPermission(INTENT_READ);
Thomas Vachuskac46af202015-06-03 16:43:27 -0700178 return store.getIntentData(false, 0);
179 }
180
181 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700182 public long getIntentCount() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900183 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700184 return store.getIntentCount();
185 }
186
187 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800188 public IntentState getIntentState(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900189 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800190 checkNotNull(intentKey, INTENT_ID_NULL);
191 return store.getIntentState(intentKey);
Brian O'Connor66630c82014-10-02 21:08:19 -0700192 }
193
194 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800195 public List<Intent> getInstallableIntents(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900196 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800197 checkNotNull(intentKey, INTENT_ID_NULL);
198 return store.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700199 }
200
201 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800202 public boolean isLocal(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900203 checkPermission(INTENT_READ);
Brian O'Connorbe28a872015-02-19 21:44:37 -0800204 return store.isMaster(intentKey);
205 }
206
207 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700208 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800209 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700210 }
211
212 @Override
213 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800214 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700215 }
216
217 @Override
218 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800219 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700220 }
221
222 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800223 public Iterable<Intent> getPending() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900224 checkPermission(INTENT_READ);
Changhoon Yoon541ef712015-05-23 17:18:34 +0900225
Jonathan Hart34f1e382015-02-24 16:52:23 -0800226 return store.getPending();
227 }
228
Brian O'Connor66630c82014-10-02 21:08:19 -0700229 // Store delegate to re-post events emitted from the store.
230 private class InternalStoreDelegate implements IntentStoreDelegate {
231 @Override
232 public void notify(IntentEvent event) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700233 post(event);
Brian O'Connor66630c82014-10-02 21:08:19 -0700234 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800235
236 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800237 public void process(IntentData data) {
238 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800239 }
Thomas Vachuskac46af202015-06-03 16:43:27 -0700240
241 @Override
242 public void onUpdate(IntentData intentData) {
243 trackerService.trackIntent(intentData);
244 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700245 }
246
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800247 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800248 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800249 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800250 for (Key key : intentKeys) {
251 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800252 if (intent == null) {
253 continue;
254 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800255 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800256 }
257
Jonathan Hart0cca3e82015-09-23 17:54:11 -0700258 if (compileAllFailed) {
259 // If required, compile all currently failed intents.
260 for (Intent intent : getIntents()) {
261 IntentState state = getIntentState(intent.key());
262 if (RECOMPILE.contains(state) || intentAllowsPartialFailure(intent)) {
263 if (WITHDRAW.contains(state)) {
264 withdraw(intent);
265 } else {
266 submit(intent);
267 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800268 }
269 }
270 }
271
Brian O'Connorb499b352015-02-03 16:46:15 -0800272 //FIXME
273// for (ApplicationId appId : batches.keySet()) {
274// if (batchService.isLocalLeader(appId)) {
275// execute(batches.get(appId).build());
276// }
277// }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800278 }
279
tom95329eb2014-10-06 08:40:06 -0700280 // Topology change delegate
281 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
282 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800283 public void triggerCompile(Iterable<Key> intentKeys,
tom85258ee2014-10-07 00:10:02 -0700284 boolean compileAllFailed) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800285 buildAndSubmitBatches(intentKeys, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700286 }
tom95329eb2014-10-06 08:40:06 -0700287 }
tom85258ee2014-10-07 00:10:02 -0700288
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800289 private Future<FinalIntentProcessPhase> submitIntentData(IntentData data) {
Sho SHIMIZU0cb6fe62015-02-23 16:39:57 -0800290 IntentData current = store.getIntentData(data.key());
Sho SHIMIZUce49b602015-02-23 19:15:49 -0800291 IntentProcessPhase initial = newInitialPhase(processor, data, current);
Sho SHIMIZU89925242016-01-13 14:20:34 -0800292 return workerExecutor.submit(() -> {
293 Optional<IntentProcessPhase> currentPhase = Optional.of(initial);
294 IntentProcessPhase previousPhase = initial;
295
296 while (currentPhase.isPresent()) {
297 previousPhase = currentPhase.get();
298 currentPhase = previousPhase.execute();
299 }
300 return (FinalIntentProcessPhase) previousPhase;
301 });
Sho SHIMIZU8d9d1362015-02-04 12:28:15 -0800302 }
303
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800304 private class IntentBatchProcess implements Runnable {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800305
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800306 protected final Collection<IntentData> data;
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800307
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800308 IntentBatchProcess(Collection<IntentData> data) {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800309 this.data = checkNotNull(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800310 }
311
312 @Override
313 public void run() {
314 try {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800315 /*
316 1. wrap each intentdata in a runnable and submit
317 2. wait for completion of all the work
318 3. accumulate results and submit batch write of IntentData to store
319 (we can also try to update these individually)
320 */
321 submitUpdates(waitForFutures(createIntentUpdates()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800322 } catch (Exception e) {
323 log.error("Error submitting batches:", e);
324 // FIXME incomplete Intents should be cleaned up
325 // (transition to FAILED, etc.)
326
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800327 // the batch has failed
328 // TODO: maybe we should do more?
329 log.error("Walk the plank, matey...");
Brian O'Connorb499b352015-02-03 16:46:15 -0800330 //FIXME
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800331// batchService.removeIntentOperations(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800332 }
Brian O'Connor3c4b00d2015-02-22 20:42:26 -0800333 accumulator.ready();
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800334 }
335
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800336 private List<Future<FinalIntentProcessPhase>> createIntentUpdates() {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800337 return data.stream()
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800338 .map(IntentManager.this::submitIntentData)
339 .collect(Collectors.toList());
340 }
341
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800342 private List<FinalIntentProcessPhase> waitForFutures(List<Future<FinalIntentProcessPhase>> futures) {
343 ImmutableList.Builder<FinalIntentProcessPhase> updateBuilder = ImmutableList.builder();
344 for (Future<FinalIntentProcessPhase> future : futures) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800345 try {
346 updateBuilder.add(future.get());
347 } catch (InterruptedException | ExecutionException e) {
348 //FIXME
349 log.warn("Future failed: {}", e);
350 }
351 }
352 return updateBuilder.build();
353 }
354
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800355 private void submitUpdates(List<FinalIntentProcessPhase> updates) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800356 store.batchWrite(updates.stream()
Brian O'Connorb5dcc512015-03-24 17:28:00 -0700357 .map(FinalIntentProcessPhase::data)
358 .collect(Collectors.toList()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800359 }
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800360 }
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800361
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700362 private class InternalBatchDelegate implements IntentBatchDelegate {
363 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800364 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800365 log.debug("Execute {} operation(s).", operations.size());
366 log.trace("Execute operations: {}", operations);
Sho SHIMIZU94b03b12015-04-10 14:53:13 -0700367
368 // batchExecutor is single-threaded, so only one batch is in flight at a time
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800369 batchExecutor.execute(new IntentBatchProcess(operations));
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700370 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700371 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800372
373 private class InternalIntentProcessor implements IntentProcessor {
374 @Override
375 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
376 return compilerRegistry.compile(intent, previousInstallables);
377 }
378
379 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700380 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700381 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800382 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700383 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800384
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700385 private enum Direction {
386 ADD,
387 REMOVE
388 }
389
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700390 private void applyIntentData(Optional<IntentData> intentData,
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700391 FlowRuleOperations.Builder builder,
392 Direction direction) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700393 if (!intentData.isPresent()) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700394 return;
395 }
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700396 IntentData data = intentData.get();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700397
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700398 List<Intent> intentsToApply = data.installables();
399 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
400 throw new IllegalStateException("installable intents must be FlowRuleIntent");
401 }
402
403 if (direction == Direction.ADD) {
404 trackerService.addTrackedResources(data.key(), data.intent().resources());
405 intentsToApply.forEach(installable ->
406 trackerService.addTrackedResources(data.key(), installable.resources()));
407 } else {
408 trackerService.removeTrackedResources(data.key(), data.intent().resources());
409 intentsToApply.forEach(installable ->
410 trackerService.removeTrackedResources(data.intent().key(),
411 installable.resources()));
412 }
413
414 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
415 builder.newStage();
416
417 List<Collection<FlowRule>> stages = intentsToApply.stream()
418 .map(x -> (FlowRuleIntent) x)
419 .map(FlowRuleIntent::flowRules)
420 .collect(Collectors.toList());
421
422 for (Collection<FlowRule> rules : stages) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700423 if (direction == Direction.ADD) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700424 rules.forEach(builder::add);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700425 } else {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700426 rules.forEach(builder::remove);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700427 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800428 }
429
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800430 }
431
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700432 private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800433 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800434
435 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700436 applyIntentData(toUninstall, builder, Direction.REMOVE);
437 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800438
439 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
440 @Override
441 public void onSuccess(FlowRuleOperations ops) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700442 if (toInstall.isPresent()) {
443 IntentData installData = toInstall.get();
444 log.debug("Completed installing: {}", installData.key());
445 installData.setState(INSTALLED);
446 store.write(installData);
447 } else if (toUninstall.isPresent()) {
448 IntentData uninstallData = toUninstall.get();
449 log.debug("Completed withdrawing: {}", uninstallData.key());
450 switch (uninstallData.request()) {
451 case INSTALL_REQ:
452 uninstallData.setState(FAILED);
453 break;
454 case WITHDRAW_REQ:
455 default: //TODO "default" case should not happen
456 uninstallData.setState(WITHDRAWN);
457 break;
458 }
459 store.write(uninstallData);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700460 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800461 }
462
463 @Override
464 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700465 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700466 if (toInstall.isPresent()) {
467 IntentData installData = toInstall.get();
468 log.warn("Failed installation: {} {} on {}",
469 installData.key(), installData.intent(), ops);
470 installData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700471 installData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700472 store.write(installData);
473 }
Sho SHIMIZUd4936252015-04-10 15:03:57 -0700474 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700475 if (toUninstall.isPresent()) {
476 IntentData uninstallData = toUninstall.get();
477 log.warn("Failed withdrawal: {} {} on {}",
478 uninstallData.key(), uninstallData.intent(), ops);
479 uninstallData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700480 uninstallData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700481 store.write(uninstallData);
482 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800483 }
484 });
485
Brian O'Connora7674262015-06-04 13:55:18 -0700486 if (log.isTraceEnabled()) {
487 log.trace("applying intent {} -> {} with {} rules: {}",
488 toUninstall.isPresent() ? toUninstall.get().key() : "<empty>",
489 toInstall.isPresent() ? toInstall.get().key() : "<empty>",
490 operations.stages().stream().mapToLong(i -> i.size()).sum(),
491 operations.stages());
492 }
493
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800494 flowRuleService.apply(operations);
495 }
496
Brian O'Connor66630c82014-10-02 21:08:19 -0700497}