blob: 082f4a3f8d644d424fda5d17884976f951698e59 [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'Connor66630c82014-10-02 21:08:19 -070018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
23import org.apache.felix.scr.annotations.Service;
Sho SHIMIZUe0981722016-01-14 16:02:48 -080024import org.onlab.util.Tools;
Brian O'Connorabafb502014-12-02 22:26:20 -080025import org.onosproject.core.CoreService;
26import org.onosproject.core.IdGenerator;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080027import org.onosproject.event.AbstractListenerManager;
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;
Sho SHIMIZUab541a52016-01-13 23:29:32 -080053import java.util.Objects;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070054import java.util.Optional;
Sho SHIMIZUad8ab272016-01-13 22:08:58 -080055import java.util.concurrent.CompletableFuture;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070056import java.util.concurrent.ExecutorService;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070057import 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;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080063import static org.onosproject.net.intent.IntentState.CORRUPT;
64import static org.onosproject.net.intent.IntentState.FAILED;
65import static org.onosproject.net.intent.IntentState.INSTALLED;
66import static org.onosproject.net.intent.IntentState.INSTALL_REQ;
67import static org.onosproject.net.intent.IntentState.WITHDRAWING;
68import static org.onosproject.net.intent.IntentState.WITHDRAWN;
69import static org.onosproject.net.intent.IntentState.WITHDRAW_REQ;
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070070import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080071import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
Changhoon Yoon541ef712015-05-23 17:18:34 +090072import static org.onosproject.security.AppGuard.checkPermission;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080073import static org.onosproject.security.AppPermission.Type.INTENT_READ;
74import static org.onosproject.security.AppPermission.Type.INTENT_WRITE;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070075import static org.slf4j.LoggerFactory.getLogger;
Changhoon Yoonb856b812015-08-10 03:47:19 +090076
Brian O'Connor66630c82014-10-02 21:08:19 -070077
78/**
Brian O'Connorce2d8b52015-07-29 16:24:13 -070079 * An implementation of intent service.
Brian O'Connor66630c82014-10-02 21:08:19 -070080 */
81@Component(immediate = true)
82@Service
83public class IntentManager
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070084 extends AbstractListenerManager<IntentEvent, IntentListener>
Brian O'Connor66630c82014-10-02 21:08:19 -070085 implements IntentService, IntentExtensionService {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070086
Sho SHIMIZU8b5051d2014-11-05 11:24:13 -080087 private static final Logger log = getLogger(IntentManager.class);
Brian O'Connor66630c82014-10-02 21:08:19 -070088
89 public static final String INTENT_NULL = "Intent cannot be null";
Ray Milkeyf9af43c2015-02-09 16:45:48 -080090 public static final String INTENT_ID_NULL = "Intent key cannot be null";
Brian O'Connor66630c82014-10-02 21:08:19 -070091
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080092 private static final int NUM_THREADS = 12;
93
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080094 private static final EnumSet<IntentState> RECOMPILE
95 = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070096 private static final EnumSet<IntentState> WITHDRAW
97 = EnumSet.of(WITHDRAW_REQ, WITHDRAWING, WITHDRAWN);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080098
Brian O'Connor520c0522014-11-23 23:50:47 -080099 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected CoreService coreService;
Brian O'Connor66630c82014-10-02 21:08:19 -0700101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected IntentStore store;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -0700106 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -0700107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZU214ac322015-02-23 19:30:15 -0800109 protected FlowRuleService flowRuleService;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700110
Brian O'Connordb15b042015-02-04 14:59:28 -0800111 private ExecutorService batchExecutor;
112 private ExecutorService workerExecutor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800113
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800114 private final CompilerRegistry compilerRegistry = new CompilerRegistry();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800115 private final InternalIntentProcessor processor = new InternalIntentProcessor();
Brian O'Connor520c0522014-11-23 23:50:47 -0800116 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
117 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
118 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
119 private IdGenerator idGenerator;
120
Brian O'Connorb499b352015-02-03 16:46:15 -0800121 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800122
Brian O'Connor66630c82014-10-02 21:08:19 -0700123 @Activate
124 public void activate() {
125 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700126 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700127 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorbdc7f002015-02-18 20:49:41 -0800128 batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch"));
129 workerExecutor = newFixedThreadPool(NUM_THREADS, groupedThreads("onos/intent", "worker-%d"));
Brian O'Connor520c0522014-11-23 23:50:47 -0800130 idGenerator = coreService.getIdGenerator("intent-ids");
131 Intent.bindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700132 log.info("Started");
133 }
134
135 @Deactivate
136 public void deactivate() {
137 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700138 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700139 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connordb15b042015-02-04 14:59:28 -0800140 batchExecutor.shutdown();
Brian O'Connor3c58e962015-04-28 23:21:51 -0700141 workerExecutor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800142 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700143 log.info("Stopped");
144 }
145
146 @Override
147 public void submit(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900148 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700149 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800150 IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800151 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700152 }
153
154 @Override
155 public void withdraw(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900156 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700157 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800158 IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800159 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700160 }
161
Brian O'Connor66630c82014-10-02 21:08:19 -0700162 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700163 public void purge(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900164 checkPermission(INTENT_WRITE);
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 Yoonb856b812015-08-10 03:47:19 +0900172 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800173 return store.getIntent(key);
174 }
175
176 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700177 public Iterable<Intent> getIntents() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900178 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700179 return store.getIntents();
180 }
181
182 @Override
Thomas Vachuskac46af202015-06-03 16:43:27 -0700183 public Iterable<IntentData> getIntentData() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900184 checkPermission(INTENT_READ);
Thomas Vachuskac46af202015-06-03 16:43:27 -0700185 return store.getIntentData(false, 0);
186 }
187
188 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700189 public long getIntentCount() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900190 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700191 return store.getIntentCount();
192 }
193
194 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800195 public IntentState getIntentState(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.getIntentState(intentKey);
Brian O'Connor66630c82014-10-02 21:08:19 -0700199 }
200
201 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800202 public List<Intent> getInstallableIntents(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900203 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800204 checkNotNull(intentKey, INTENT_ID_NULL);
205 return store.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700206 }
207
208 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800209 public boolean isLocal(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900210 checkPermission(INTENT_READ);
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 <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800216 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700217 }
218
219 @Override
220 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800221 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700222 }
223
224 @Override
225 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800226 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700227 }
228
229 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800230 public Iterable<Intent> getPending() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900231 checkPermission(INTENT_READ);
Changhoon Yoon541ef712015-05-23 17:18:34 +0900232
Jonathan Hart34f1e382015-02-24 16:52:23 -0800233 return store.getPending();
234 }
235
Brian O'Connor66630c82014-10-02 21:08:19 -0700236 // Store delegate to re-post events emitted from the store.
237 private class InternalStoreDelegate implements IntentStoreDelegate {
238 @Override
239 public void notify(IntentEvent event) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700240 post(event);
Brian O'Connor66630c82014-10-02 21:08:19 -0700241 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800242
243 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800244 public void process(IntentData data) {
245 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800246 }
Thomas Vachuskac46af202015-06-03 16:43:27 -0700247
248 @Override
249 public void onUpdate(IntentData intentData) {
250 trackerService.trackIntent(intentData);
251 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700252 }
253
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800254 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800255 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800256 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800257 for (Key key : intentKeys) {
258 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800259 if (intent == null) {
260 continue;
261 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800262 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800263 }
264
Jonathan Hart0cca3e82015-09-23 17:54:11 -0700265 if (compileAllFailed) {
266 // If required, compile all currently failed intents.
267 for (Intent intent : getIntents()) {
268 IntentState state = getIntentState(intent.key());
269 if (RECOMPILE.contains(state) || intentAllowsPartialFailure(intent)) {
270 if (WITHDRAW.contains(state)) {
271 withdraw(intent);
272 } else {
273 submit(intent);
274 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800275 }
276 }
277 }
278
Brian O'Connorb499b352015-02-03 16:46:15 -0800279 //FIXME
280// for (ApplicationId appId : batches.keySet()) {
281// if (batchService.isLocalLeader(appId)) {
282// execute(batches.get(appId).build());
283// }
284// }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800285 }
286
tom95329eb2014-10-06 08:40:06 -0700287 // Topology change delegate
288 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
289 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800290 public void triggerCompile(Iterable<Key> intentKeys,
tom85258ee2014-10-07 00:10:02 -0700291 boolean compileAllFailed) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800292 buildAndSubmitBatches(intentKeys, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700293 }
tom95329eb2014-10-06 08:40:06 -0700294 }
tom85258ee2014-10-07 00:10:02 -0700295
Sho SHIMIZUad8ab272016-01-13 22:08:58 -0800296 private CompletableFuture<FinalIntentProcessPhase> submitIntentData(IntentData data) {
Sho SHIMIZU594fb2a2016-01-14 16:12:26 -0800297 IntentProcessPhase initial = createInitialPhase(data);
298 return CompletableFuture.supplyAsync(() -> process(initial), workerExecutor);
299 }
Sho SHIMIZU89925242016-01-13 14:20:34 -0800300
Sho SHIMIZU594fb2a2016-01-14 16:12:26 -0800301 private IntentProcessPhase createInitialPhase(IntentData data) {
302 IntentData current = store.getIntentData(data.key());
303 return newInitialPhase(processor, data, current);
304 }
305
306 private FinalIntentProcessPhase process(IntentProcessPhase initial) {
307 Optional<IntentProcessPhase> currentPhase = Optional.of(initial);
308 IntentProcessPhase previousPhase = initial;
309
310 while (currentPhase.isPresent()) {
311 previousPhase = currentPhase.get();
312 currentPhase = previousPhase.execute();
313 }
314 return (FinalIntentProcessPhase) previousPhase;
Sho SHIMIZU8d9d1362015-02-04 12:28:15 -0800315 }
316
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700317 private class InternalBatchDelegate implements IntentBatchDelegate {
318 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800319 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800320 log.debug("Execute {} operation(s).", operations.size());
321 log.trace("Execute operations: {}", operations);
Sho SHIMIZU94b03b12015-04-10 14:53:13 -0700322
323 // batchExecutor is single-threaded, so only one batch is in flight at a time
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800324 batchExecutor.execute(() -> {
325 try {
326 /*
327 1. wrap each intentdata in a runnable and submit
328 2. wait for completion of all the work
329 3. accumulate results and submit batch write of IntentData to store
330 (we can also try to update these individually)
331 */
Sho SHIMIZUe0981722016-01-14 16:02:48 -0800332 List<CompletableFuture<IntentData>> futures = operations.stream()
Sho SHIMIZUd7558932016-01-13 23:47:46 -0800333 .map(IntentManager.this::submitIntentData)
Sho SHIMIZUe0981722016-01-14 16:02:48 -0800334 .map(x -> x.thenApply(FinalIntentProcessPhase::data))
Sho SHIMIZUd7558932016-01-13 23:47:46 -0800335 .map(x -> x.exceptionally(e -> {
336 //FIXME
337 log.warn("Future failed: {}", e);
338 return null;
339 }))
Sho SHIMIZUe0981722016-01-14 16:02:48 -0800340 .collect(Collectors.toList());
341 store.batchWrite(Tools.allOf(futures).join().stream()
Sho SHIMIZUd7558932016-01-13 23:47:46 -0800342 .filter(Objects::nonNull)
Sho SHIMIZUd7558932016-01-13 23:47:46 -0800343 .collect(Collectors.toList()));
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800344 } catch (Exception e) {
345 log.error("Error submitting batches:", e);
346 // FIXME incomplete Intents should be cleaned up
347 // (transition to FAILED, etc.)
348
349 // the batch has failed
350 // TODO: maybe we should do more?
351 log.error("Walk the plank, matey...");
352 //FIXME
353// batchService.removeIntentOperations(data);
354 }
355 accumulator.ready();
356 });
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700357 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700358 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800359
360 private class InternalIntentProcessor implements IntentProcessor {
361 @Override
362 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
363 return compilerRegistry.compile(intent, previousInstallables);
364 }
365
366 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700367 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700368 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800369 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700370 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800371
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700372 private enum Direction {
373 ADD,
374 REMOVE
375 }
376
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700377 private void applyIntentData(Optional<IntentData> intentData,
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700378 FlowRuleOperations.Builder builder,
379 Direction direction) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700380 if (!intentData.isPresent()) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700381 return;
382 }
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700383 IntentData data = intentData.get();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700384
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700385 List<Intent> intentsToApply = data.installables();
386 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
387 throw new IllegalStateException("installable intents must be FlowRuleIntent");
388 }
389
390 if (direction == Direction.ADD) {
391 trackerService.addTrackedResources(data.key(), data.intent().resources());
392 intentsToApply.forEach(installable ->
393 trackerService.addTrackedResources(data.key(), installable.resources()));
394 } else {
395 trackerService.removeTrackedResources(data.key(), data.intent().resources());
396 intentsToApply.forEach(installable ->
397 trackerService.removeTrackedResources(data.intent().key(),
398 installable.resources()));
399 }
400
401 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
402 builder.newStage();
403
404 List<Collection<FlowRule>> stages = intentsToApply.stream()
405 .map(x -> (FlowRuleIntent) x)
406 .map(FlowRuleIntent::flowRules)
407 .collect(Collectors.toList());
408
409 for (Collection<FlowRule> rules : stages) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700410 if (direction == Direction.ADD) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700411 rules.forEach(builder::add);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700412 } else {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700413 rules.forEach(builder::remove);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700414 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800415 }
416
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800417 }
418
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700419 private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800420 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800421
422 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700423 applyIntentData(toUninstall, builder, Direction.REMOVE);
424 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800425
426 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
427 @Override
428 public void onSuccess(FlowRuleOperations ops) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700429 if (toInstall.isPresent()) {
430 IntentData installData = toInstall.get();
431 log.debug("Completed installing: {}", installData.key());
432 installData.setState(INSTALLED);
433 store.write(installData);
434 } else if (toUninstall.isPresent()) {
435 IntentData uninstallData = toUninstall.get();
436 log.debug("Completed withdrawing: {}", uninstallData.key());
437 switch (uninstallData.request()) {
438 case INSTALL_REQ:
439 uninstallData.setState(FAILED);
440 break;
441 case WITHDRAW_REQ:
442 default: //TODO "default" case should not happen
443 uninstallData.setState(WITHDRAWN);
444 break;
445 }
446 store.write(uninstallData);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700447 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800448 }
449
450 @Override
451 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700452 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700453 if (toInstall.isPresent()) {
454 IntentData installData = toInstall.get();
455 log.warn("Failed installation: {} {} on {}",
456 installData.key(), installData.intent(), ops);
457 installData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700458 installData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700459 store.write(installData);
460 }
Sho SHIMIZUd4936252015-04-10 15:03:57 -0700461 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700462 if (toUninstall.isPresent()) {
463 IntentData uninstallData = toUninstall.get();
464 log.warn("Failed withdrawal: {} {} on {}",
465 uninstallData.key(), uninstallData.intent(), ops);
466 uninstallData.setState(CORRUPT);
Brian O'Connor6d8e3172015-04-30 15:43:57 -0700467 uninstallData.incrementErrorCount();
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700468 store.write(uninstallData);
469 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800470 }
471 });
472
Brian O'Connora7674262015-06-04 13:55:18 -0700473 if (log.isTraceEnabled()) {
474 log.trace("applying intent {} -> {} with {} rules: {}",
Sho SHIMIZU98c0a392016-01-14 18:40:53 -0800475 toUninstall.map(x -> x.key().toString()).orElse("<empty>"),
476 toInstall.map(x -> x.key().toString()).orElse("<empty>"),
477 operations.stages().stream().mapToLong(i -> i.size()).sum(),
478 operations.stages());
Brian O'Connora7674262015-06-04 13:55:18 -0700479 }
480
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800481 flowRuleService.apply(operations);
482 }
483
Brian O'Connor66630c82014-10-02 21:08:19 -0700484}