blob: 9df63ae332058ecb4f4842535f494e23a7c1bf39 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
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'Connor03406a42015-02-03 17:28:57 -080018import java.util.ArrayList;
19import java.util.Collection;
20import java.util.Collections;
21import java.util.EnumSet;
22import java.util.LinkedList;
23import java.util.List;
24import java.util.Map;
25import java.util.Optional;
26import java.util.concurrent.ConcurrentHashMap;
27import java.util.concurrent.ConcurrentMap;
28import java.util.concurrent.ExecutionException;
29import java.util.concurrent.ExecutorService;
30import java.util.concurrent.Future;
31import java.util.concurrent.TimeUnit;
32import java.util.concurrent.TimeoutException;
33import java.util.stream.Collectors;
34
Brian O'Connor66630c82014-10-02 21:08:19 -070035import org.apache.felix.scr.annotations.Activate;
36import org.apache.felix.scr.annotations.Component;
37import org.apache.felix.scr.annotations.Deactivate;
38import org.apache.felix.scr.annotations.Reference;
39import org.apache.felix.scr.annotations.ReferenceCardinality;
40import org.apache.felix.scr.annotations.Service;
Brian O'Connorabafb502014-12-02 22:26:20 -080041import org.onosproject.core.CoreService;
42import org.onosproject.core.IdGenerator;
43import org.onosproject.event.AbstractListenerRegistry;
44import org.onosproject.event.EventDeliveryService;
45import org.onosproject.net.flow.CompletedBatchOperation;
46import org.onosproject.net.flow.FlowRuleBatchOperation;
47import org.onosproject.net.flow.FlowRuleService;
Brian O'Connorb499b352015-02-03 16:46:15 -080048import org.onosproject.net.intent.BatchWrite;
Brian O'Connorabafb502014-12-02 22:26:20 -080049import org.onosproject.net.intent.Intent;
50import org.onosproject.net.intent.IntentBatchDelegate;
Brian O'Connorabafb502014-12-02 22:26:20 -080051import org.onosproject.net.intent.IntentCompiler;
Brian O'Connorcff03322015-02-03 15:28:59 -080052import org.onosproject.net.intent.IntentData;
Brian O'Connorabafb502014-12-02 22:26:20 -080053import org.onosproject.net.intent.IntentEvent;
54import org.onosproject.net.intent.IntentException;
55import org.onosproject.net.intent.IntentExtensionService;
56import org.onosproject.net.intent.IntentId;
57import org.onosproject.net.intent.IntentInstaller;
58import org.onosproject.net.intent.IntentListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080059import org.onosproject.net.intent.IntentService;
60import org.onosproject.net.intent.IntentState;
61import org.onosproject.net.intent.IntentStore;
Brian O'Connorabafb502014-12-02 22:26:20 -080062import org.onosproject.net.intent.IntentStoreDelegate;
Brian O'Connor66630c82014-10-02 21:08:19 -070063import org.slf4j.Logger;
64
Brian O'Connor03406a42015-02-03 17:28:57 -080065import com.google.common.collect.ImmutableList;
66import com.google.common.collect.ImmutableMap;
67import com.google.common.collect.Lists;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070068
Brian O'Connorfa81eae2014-10-30 13:20:05 -070069import static com.google.common.base.Preconditions.checkNotNull;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080070import static java.util.concurrent.Executors.newFixedThreadPool;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070071import static org.onlab.util.Tools.namedThreads;
Brian O'Connor03406a42015-02-03 17:28:57 -080072import static org.onosproject.net.intent.IntentState.FAILED;
73import static org.onosproject.net.intent.IntentState.INSTALLED;
74import static org.onosproject.net.intent.IntentState.INSTALLING;
75import static org.onosproject.net.intent.IntentState.INSTALL_REQ;
76import static org.onosproject.net.intent.IntentState.WITHDRAWN;
77import static org.onosproject.net.intent.IntentState.WITHDRAW_REQ;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070078import static org.slf4j.LoggerFactory.getLogger;
Brian O'Connor66630c82014-10-02 21:08:19 -070079
80/**
81 * An implementation of Intent Manager.
82 */
83@Component(immediate = true)
84@Service
85public class IntentManager
86 implements IntentService, IntentExtensionService {
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";
90 public static final String INTENT_ID_NULL = "Intent ID cannot be null";
91
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);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080096
97
Brian O'Connor66630c82014-10-02 21:08:19 -070098 // Collections for compiler, installer, and listener are ONOS instance local
99 private final ConcurrentMap<Class<? extends Intent>,
100 IntentCompiler<? extends Intent>> compilers = new ConcurrentHashMap<>();
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700101 private final ConcurrentMap<Class<? extends Intent>,
102 IntentInstaller<? extends Intent>> installers = new ConcurrentHashMap<>();
Brian O'Connor66630c82014-10-02 21:08:19 -0700103
104 private final AbstractListenerRegistry<IntentEvent, IntentListener>
tom95329eb2014-10-06 08:40:06 -0700105 listenerRegistry = new AbstractListenerRegistry<>();
Brian O'Connor66630c82014-10-02 21:08:19 -0700106
Brian O'Connor520c0522014-11-23 23:50:47 -0800107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected CoreService coreService;
Brian O'Connor66630c82014-10-02 21:08:19 -0700109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected IntentStore store;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -0700114 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -0700115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Brian O'Connor66630c82014-10-02 21:08:19 -0700117 protected EventDeliveryService eventDispatcher;
118
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected FlowRuleService flowRuleService;
121
Brian O'Connor520c0522014-11-23 23:50:47 -0800122
123 private ExecutorService executor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800124
125 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
126 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
127 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
128 private IdGenerator idGenerator;
129
Brian O'Connorb499b352015-02-03 16:46:15 -0800130 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800131
Brian O'Connor66630c82014-10-02 21:08:19 -0700132 @Activate
133 public void activate() {
134 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700135 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700136 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Yuta HIGUCHI7a9fddd2014-12-03 15:30:25 -0800137 executor = newFixedThreadPool(NUM_THREADS, namedThreads("onos-intent-%d"));
Brian O'Connor520c0522014-11-23 23:50:47 -0800138 idGenerator = coreService.getIdGenerator("intent-ids");
139 Intent.bindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700140 log.info("Started");
141 }
142
143 @Deactivate
144 public void deactivate() {
145 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700146 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700147 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connorcb900f42014-10-07 21:55:33 -0700148 executor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800149 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700150 log.info("Stopped");
151 }
152
153 @Override
154 public void submit(Intent intent) {
155 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800156 IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null);
157 //FIXME timestamp?
158 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700159 }
160
161 @Override
162 public void withdraw(Intent intent) {
163 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800164 IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null);
165 //FIXME timestamp?
166 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700167 }
168
Brian O'Connor66630c82014-10-02 21:08:19 -0700169 @Override
Thomas Vachuska83e090e2014-10-22 14:25:35 -0700170 public void replace(IntentId oldIntentId, Intent newIntent) {
Brian O'Connorcff03322015-02-03 15:28:59 -0800171 throw new UnsupportedOperationException("replace is not implemented");
Thomas Vachuska83e090e2014-10-22 14:25:35 -0700172 }
173
Thomas Vachuska83e090e2014-10-22 14:25:35 -0700174 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700175 public Iterable<Intent> getIntents() {
176 return store.getIntents();
177 }
178
179 @Override
180 public long getIntentCount() {
181 return store.getIntentCount();
182 }
183
184 @Override
185 public Intent getIntent(IntentId id) {
186 checkNotNull(id, INTENT_ID_NULL);
187 return store.getIntent(id);
188 }
189
190 @Override
191 public IntentState getIntentState(IntentId id) {
192 checkNotNull(id, INTENT_ID_NULL);
193 return store.getIntentState(id);
194 }
195
196 @Override
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700197 public List<Intent> getInstallableIntents(IntentId intentId) {
198 checkNotNull(intentId, INTENT_ID_NULL);
199 return store.getInstallableIntents(intentId);
200 }
201
202 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700203 public void addListener(IntentListener listener) {
204 listenerRegistry.addListener(listener);
205 }
206
207 @Override
208 public void removeListener(IntentListener listener) {
209 listenerRegistry.removeListener(listener);
210 }
211
212 @Override
213 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
214 compilers.put(cls, compiler);
215 }
216
217 @Override
218 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
219 compilers.remove(cls);
220 }
221
222 @Override
223 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
224 return ImmutableMap.copyOf(compilers);
225 }
226
227 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700228 public <T extends Intent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700229 installers.put(cls, installer);
230 }
231
232 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700233 public <T extends Intent> void unregisterInstaller(Class<T> cls) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700234 installers.remove(cls);
235 }
236
237 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700238 public Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> getInstallers() {
Brian O'Connor66630c82014-10-02 21:08:19 -0700239 return ImmutableMap.copyOf(installers);
240 }
241
242 /**
Brian O'Connor66630c82014-10-02 21:08:19 -0700243 * Returns the corresponding intent compiler to the specified intent.
244 *
245 * @param intent intent
tom95329eb2014-10-06 08:40:06 -0700246 * @param <T> the type of intent
Brian O'Connor66630c82014-10-02 21:08:19 -0700247 * @return intent compiler corresponding to the specified intent
248 */
249 private <T extends Intent> IntentCompiler<T> getCompiler(T intent) {
250 @SuppressWarnings("unchecked")
251 IntentCompiler<T> compiler = (IntentCompiler<T>) compilers.get(intent.getClass());
252 if (compiler == null) {
253 throw new IntentException("no compiler for class " + intent.getClass());
254 }
255 return compiler;
256 }
257
258 /**
259 * Returns the corresponding intent installer to the specified installable intent.
tom95329eb2014-10-06 08:40:06 -0700260 *
Brian O'Connor66630c82014-10-02 21:08:19 -0700261 * @param intent intent
tom95329eb2014-10-06 08:40:06 -0700262 * @param <T> the type of installable intent
Brian O'Connor66630c82014-10-02 21:08:19 -0700263 * @return intent installer corresponding to the specified installable intent
264 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700265 private <T extends Intent> IntentInstaller<T> getInstaller(T intent) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700266 @SuppressWarnings("unchecked")
267 IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent.getClass());
268 if (installer == null) {
269 throw new IntentException("no installer for class " + intent.getClass());
270 }
271 return installer;
272 }
273
274 /**
Brian O'Connorcb900f42014-10-07 21:55:33 -0700275 * Compiles an intent recursively.
276 *
277 * @param intent intent
278 * @return result of compilation
279 */
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800280 private List<Intent> compileIntent(Intent intent, List<Intent> previousInstallables) {
Thomas Vachuska4926c1b2014-10-21 00:44:10 -0700281 if (intent.isInstallable()) {
282 return ImmutableList.of(intent);
Brian O'Connor66630c82014-10-02 21:08:19 -0700283 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700284
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700285 registerSubclassCompilerIfNeeded(intent);
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700286 // FIXME: get previous resources
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700287 List<Intent> installable = new ArrayList<>();
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800288 for (Intent compiled : getCompiler(intent).compile(intent, previousInstallables, null)) {
289 installable.addAll(compileIntent(compiled, previousInstallables));
Brian O'Connorcb900f42014-10-07 21:55:33 -0700290 }
tom85258ee2014-10-07 00:10:02 -0700291 return installable;
Brian O'Connor66630c82014-10-02 21:08:19 -0700292 }
293
294 /**
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700295 * Uninstalls all installable intents associated with the given intent.
296 *
Brian O'Connor427a1762014-11-19 18:40:32 -0800297 * @param intent intent
298 * @param installables installable intents
299 * @return list of batches to uninstall intent
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700300 */
Brian O'Connor427a1762014-11-19 18:40:32 -0800301 private List<FlowRuleBatchOperation> uninstallIntent(Intent intent, List<Intent> installables) {
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700302 List<FlowRuleBatchOperation> batches = Lists.newArrayList();
Brian O'Connor427a1762014-11-19 18:40:32 -0800303 for (Intent installable : installables) {
304 trackerService.removeTrackedResources(intent.id(),
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800305 installable.resources());
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700306 try {
307 batches.addAll(getInstaller(installable).uninstall(installable));
308 } catch (IntentException e) {
Brian O'Connor427a1762014-11-19 18:40:32 -0800309 log.warn("Unable to uninstall intent {} due to:", intent.id(), e);
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700310 // TODO: this should never happen. but what if it does?
311 }
312 }
Brian O'Connor427a1762014-11-19 18:40:32 -0800313 return batches;
tom85258ee2014-10-07 00:10:02 -0700314 }
315
316 /**
Brian O'Connor66630c82014-10-02 21:08:19 -0700317 * Registers an intent compiler of the specified intent if an intent compiler
318 * for the intent is not registered. This method traverses the class hierarchy of
319 * the intent. Once an intent compiler for a parent type is found, this method
320 * registers the found intent compiler.
321 *
322 * @param intent intent
323 */
324 private void registerSubclassCompilerIfNeeded(Intent intent) {
325 if (!compilers.containsKey(intent.getClass())) {
326 Class<?> cls = intent.getClass();
327 while (cls != Object.class) {
328 // As long as we're within the Intent class descendants
329 if (Intent.class.isAssignableFrom(cls)) {
330 IntentCompiler<?> compiler = compilers.get(cls);
331 if (compiler != null) {
332 compilers.put(intent.getClass(), compiler);
333 return;
334 }
335 }
336 cls = cls.getSuperclass();
337 }
338 }
339 }
340
341 /**
342 * Registers an intent installer of the specified intent if an intent installer
343 * for the intent is not registered. This method traverses the class hierarchy of
344 * the intent. Once an intent installer for a parent type is found, this method
345 * registers the found intent installer.
346 *
347 * @param intent intent
348 */
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700349 private void registerSubclassInstallerIfNeeded(Intent intent) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700350 if (!installers.containsKey(intent.getClass())) {
351 Class<?> cls = intent.getClass();
352 while (cls != Object.class) {
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700353 // As long as we're within the Intent class descendants
354 if (Intent.class.isAssignableFrom(cls)) {
Brian O'Connor66630c82014-10-02 21:08:19 -0700355 IntentInstaller<?> installer = installers.get(cls);
356 if (installer != null) {
357 installers.put(intent.getClass(), installer);
358 return;
359 }
360 }
361 cls = cls.getSuperclass();
362 }
363 }
364 }
365
Brian O'Connor66630c82014-10-02 21:08:19 -0700366 // Store delegate to re-post events emitted from the store.
367 private class InternalStoreDelegate implements IntentStoreDelegate {
368 @Override
369 public void notify(IntentEvent event) {
tom85258ee2014-10-07 00:10:02 -0700370 eventDispatcher.post(event);
Brian O'Connor66630c82014-10-02 21:08:19 -0700371 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800372
373 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800374 public void process(IntentData data) {
375 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800376 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700377 }
378
Brian O'Connor72a034c2014-11-26 18:24:23 -0800379 private void buildAndSubmitBatches(Iterable<IntentId> intentIds,
380 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800381 // Attempt recompilation of the specified intents first.
382 for (IntentId id : intentIds) {
383 Intent intent = store.getIntent(id);
384 if (intent == null) {
385 continue;
386 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800387 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800388 }
389
390 if (compileAllFailed) {
391 // If required, compile all currently failed intents.
392 for (Intent intent : getIntents()) {
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800393 IntentState state = getIntentState(intent.id());
394 if (RECOMPILE.contains(state)) {
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800395 if (state == WITHDRAW_REQ) {
Brian O'Connor03406a42015-02-03 17:28:57 -0800396 withdraw(intent);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800397 } else {
Brian O'Connor03406a42015-02-03 17:28:57 -0800398 submit(intent);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800399 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800400 }
401 }
402 }
403
Brian O'Connorb499b352015-02-03 16:46:15 -0800404 //FIXME
405// for (ApplicationId appId : batches.keySet()) {
406// if (batchService.isLocalLeader(appId)) {
407// execute(batches.get(appId).build());
408// }
409// }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800410 }
411
tom95329eb2014-10-06 08:40:06 -0700412 // Topology change delegate
413 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
414 @Override
tom85258ee2014-10-07 00:10:02 -0700415 public void triggerCompile(Iterable<IntentId> intentIds,
416 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800417 buildAndSubmitBatches(intentIds, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700418 }
tom95329eb2014-10-06 08:40:06 -0700419 }
tom85258ee2014-10-07 00:10:02 -0700420
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800421 // TODO: simplify the branching statements
Brian O'Connorb499b352015-02-03 16:46:15 -0800422 private IntentUpdate createIntentUpdate(IntentData intentData) {
423 IntentData currentState = store.getIntentData(intentData.key());
424 switch (intentData.state()) {
425 case INSTALL_REQ:
426 return new InstallRequest(intentData.intent(), currentState);
427 case WITHDRAW_REQ:
428 return new WithdrawRequest(intentData.intent(), currentState);
429 // fallthrough
430 case COMPILING:
431 case INSTALLING:
432 case INSTALLED:
433 case RECOMPILING:
434 case WITHDRAWING:
435 case WITHDRAWN:
436 case FAILED:
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800437 default:
438 // illegal state
439 return new DoNothing();
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700440 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700441 }
442
Brian O'Connorcff03322015-02-03 15:28:59 -0800443 // TODO pull out the IntentUpdate inner classes
Sho SHIMIZU28e72712015-01-27 17:03:41 -0800444 private class InstallRequest implements IntentUpdate {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800445
446 private final Intent intent;
Brian O'Connorb499b352015-02-03 16:46:15 -0800447 private final IntentData currentState;
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800448
Brian O'Connorb499b352015-02-03 16:46:15 -0800449 InstallRequest(Intent intent, IntentData currentState) {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800450 this.intent = checkNotNull(intent);
Brian O'Connorb499b352015-02-03 16:46:15 -0800451 this.currentState = currentState;
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800452 }
453
454 @Override
455 public void writeBeforeExecution(BatchWrite batchWrite) {
456 // TODO consider only "creating" intent if it does not exist
457 // Note: We need to set state to INSTALL_REQ regardless.
458 batchWrite.createIntent(intent);
459 }
460
461 @Override
462 public Optional<IntentUpdate> execute() {
Brian O'Connorb499b352015-02-03 16:46:15 -0800463 return Optional.of(new Compiling(intent)); //FIXME
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800464 }
465 }
466
Sho SHIMIZU28e72712015-01-27 17:03:41 -0800467 private class WithdrawRequest implements IntentUpdate {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800468
469 private final Intent intent;
Brian O'Connorb499b352015-02-03 16:46:15 -0800470 private final IntentData currentState;
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800471
Brian O'Connorb499b352015-02-03 16:46:15 -0800472 WithdrawRequest(Intent intent, IntentData currentState) {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800473 this.intent = checkNotNull(intent);
Brian O'Connorb499b352015-02-03 16:46:15 -0800474 this.currentState = currentState;
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800475 }
476
477 @Override
478 public void writeBeforeExecution(BatchWrite batchWrite) {
479 batchWrite.setState(intent, WITHDRAW_REQ);
480 }
481
482 @Override
483 public Optional<IntentUpdate> execute() {
Brian O'Connorb499b352015-02-03 16:46:15 -0800484 return Optional.of(new Withdrawing(intent, currentState.installables())); //FIXME
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800485 }
486 }
487
Sho SHIMIZU28e72712015-01-27 17:03:41 -0800488 private class Compiling implements IntentUpdate {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800489
490 private final Intent intent;
491
492 Compiling(Intent intent) {
493 this.intent = checkNotNull(intent);
494 }
495
496 @Override
497 public Optional<IntentUpdate> execute() {
498 try {
499 // Compile the intent into installable derivatives.
500 // If all went well, associate the resulting list of installable
501 // intents with the top-level intent and proceed to install.
502 return Optional.of(new Installing(intent, compileIntent(intent, null)));
503 } catch (PathNotFoundException e) {
Sho SHIMIZUfd0cd8c2015-01-28 08:16:58 -0800504 log.debug("Path not found for intent {}", intent);
505 return Optional.of(new CompilingFailed(intent));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800506 } catch (IntentException e) {
Sho SHIMIZUfd0cd8c2015-01-28 08:16:58 -0800507 log.warn("Unable to compile intent {} due to:", intent.id(), e);
508 return Optional.of(new CompilingFailed(intent));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800509 }
510 }
511 }
512
513 // TODO: better naming because install() method actually generate FlowRuleBatchOperations
Sho SHIMIZU28e72712015-01-27 17:03:41 -0800514 private class Installing implements IntentUpdate {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800515
516 private final Intent intent;
517 private final List<Intent> installables;
518
519 Installing(Intent intent, List<Intent> installables) {
520 this.intent = checkNotNull(intent);
521 this.installables = ImmutableList.copyOf(checkNotNull(installables));
522 }
523
524 @Override
525 public Optional<IntentUpdate> execute() {
526 Exception exception = null;
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800527
528 List<FlowRuleBatchOperation> batches = Lists.newArrayList();
529 for (Intent installable : installables) {
530 registerSubclassInstallerIfNeeded(installable);
531 trackerService.addTrackedResources(intent.id(), installable.resources());
532 try {
533 batches.addAll(getInstaller(installable).install(installable));
534 } catch (Exception e) { // TODO this should be IntentException
535 log.warn("Unable to install intent {} due to:", intent.id(), e);
536 trackerService.removeTrackedResources(intent.id(), installable.resources());
537 //TODO we failed; intent should be recompiled
538 exception = e;
Brian O'Connor5d55ed42014-12-01 18:27:47 -0800539 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700540 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700541
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800542 if (exception != null) {
543 return Optional.of(new InstallingFailed(intent, installables, batches));
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800544 }
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800545
546 return Optional.of(new Installed(intent, installables, batches));
547 }
548 }
549
Sho SHIMIZU28e72712015-01-27 17:03:41 -0800550 private class Withdrawing implements IntentUpdate {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800551
552 private final Intent intent;
553 private final List<Intent> installables;
554
555 Withdrawing(Intent intent, List<Intent> installables) {
556 this.intent = checkNotNull(intent);
557 this.installables = ImmutableList.copyOf(installables);
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800558 }
559
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800560 @Override
561 public Optional<IntentUpdate> execute() {
562 List<FlowRuleBatchOperation> batches = uninstallIntent(intent, installables);
563
564 return Optional.of(new Withdrawn(intent, installables, batches));
565 }
566 }
567
Sho SHIMIZU28e72712015-01-27 17:03:41 -0800568 private class Installed implements CompletedIntentUpdate {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800569
570 private final Intent intent;
571 private final List<Intent> installables;
572 private IntentState intentState;
573 private final List<FlowRuleBatchOperation> batches;
574 private int currentBatch = 0;
575
576 Installed(Intent intent, List<Intent> installables, List<FlowRuleBatchOperation> batches) {
577 this.intent = checkNotNull(intent);
578 this.installables = ImmutableList.copyOf(checkNotNull(installables));
579 this.batches = new LinkedList<>(checkNotNull(batches));
580 this.intentState = INSTALLING;
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700581 }
582
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800583 @Override
584 public void batchSuccess() {
Ray Milkey93508c22014-12-02 11:35:56 -0800585 currentBatch++;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800586 }
587
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800588 @Override
589 public List<Intent> allInstallables() {
590 return installables;
591 }
592
593 @Override
594 public void writeAfterExecution(BatchWrite batchWrite) {
595 switch (intentState) {
596 case INSTALLING:
597 batchWrite.setState(intent, INSTALLED);
598 batchWrite.setInstallableIntents(intent.id(), this.installables);
599 break;
600 case FAILED:
601 batchWrite.setState(intent, FAILED);
602 batchWrite.removeInstalledIntents(intent.id());
603 break;
604 default:
605 break;
606 }
607 }
608
609 @Override
610 public FlowRuleBatchOperation currentBatch() {
611 return currentBatch < batches.size() ? batches.get(currentBatch) : null;
612 }
613
614 @Override
615 public void batchFailed() {
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800616 // the current batch has failed, so recompile
617 // remove the current batch and all remaining
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800618 for (int i = batches.size() - 1; i >= currentBatch; i--) {
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800619 batches.remove(i);
620 }
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800621 intentState = FAILED;
622 batches.addAll(uninstallIntent(intent, installables));
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800623
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800624 // TODO we might want to try to recompile the new intent
Brian O'Connor427a1762014-11-19 18:40:32 -0800625 }
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800626 }
Brian O'Connor427a1762014-11-19 18:40:32 -0800627
Sho SHIMIZU28e72712015-01-27 17:03:41 -0800628 private class Withdrawn implements CompletedIntentUpdate {
Brian O'Connor427a1762014-11-19 18:40:32 -0800629
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800630 private final Intent intent;
631 private final List<Intent> installables;
632 private final List<FlowRuleBatchOperation> batches;
633 private int currentBatch;
634
635 Withdrawn(Intent intent, List<Intent> installables, List<FlowRuleBatchOperation> batches) {
636 this.intent = checkNotNull(intent);
637 this.installables = ImmutableList.copyOf(installables);
638 this.batches = new LinkedList<>(batches);
639 this.currentBatch = 0;
640 }
641
642 @Override
643 public List<Intent> allInstallables() {
644 return installables;
645 }
646
647 @Override
648 public void batchSuccess() {
649 currentBatch++;
650 }
651
652 @Override
653 public void writeAfterExecution(BatchWrite batchWrite) {
654 batchWrite.setState(intent, WITHDRAWN);
655 batchWrite.removeInstalledIntents(intent.id());
656 batchWrite.removeIntent(intent.id());
657 }
658
659 @Override
660 public FlowRuleBatchOperation currentBatch() {
661 return currentBatch < batches.size() ? batches.get(currentBatch) : null;
662 }
663
664 @Override
665 public void batchFailed() {
666 // the current batch has failed, so recompile
667 // remove the current batch and all remaining
668 for (int i = batches.size() - 1; i >= currentBatch; i--) {
669 batches.remove(i);
Brian O'Connor427a1762014-11-19 18:40:32 -0800670 }
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800671 batches.addAll(uninstallIntent(intent, installables));
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700672 }
673 }
674
Sho SHIMIZU28e72712015-01-27 17:03:41 -0800675 private class InstallingFailed implements CompletedIntentUpdate {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800676
677 private final Intent intent;
678 private final List<Intent> installables;
679 private final List<FlowRuleBatchOperation> batches;
680 private int currentBatch = 0;
681
682 InstallingFailed(Intent intent, List<Intent> installables, List<FlowRuleBatchOperation> batches) {
683 this.intent = checkNotNull(intent);
684 this.installables = ImmutableList.copyOf(checkNotNull(installables));
685 this.batches = new LinkedList<>(checkNotNull(batches));
686 }
687
688 @Override
689 public List<Intent> allInstallables() {
690 return installables;
691 }
692
693 @Override
694 public void batchSuccess() {
695 currentBatch++;
696 }
697
698 @Override
699 public void writeAfterExecution(BatchWrite batchWrite) {
700 batchWrite.setState(intent, FAILED);
701 batchWrite.removeInstalledIntents(intent.id());
702 }
703
704 @Override
705 public FlowRuleBatchOperation currentBatch() {
706 return currentBatch < batches.size() ? batches.get(currentBatch) : null;
707 }
708
709 @Override
710 public void batchFailed() {
711 // the current batch has failed, so recompile
712 // remove the current batch and all remaining
713 for (int i = batches.size() - 1; i >= currentBatch; i--) {
714 batches.remove(i);
715 }
716 batches.addAll(uninstallIntent(intent, installables));
717
718 // TODO we might want to try to recompile the new intent
719 }
720 }
721
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800722 private class IntentBatchPreprocess implements Runnable {
723
724 // TODO make this configurable
725 private static final int TIMEOUT_PER_OP = 500; // ms
726 protected static final int MAX_ATTEMPTS = 3;
727
Brian O'Connorb499b352015-02-03 16:46:15 -0800728 protected final Collection<IntentData> ops;
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800729
730 // future holding current FlowRuleBatch installation result
731 protected final long startTime = System.currentTimeMillis();
732 protected final long endTime;
733
Brian O'Connorb499b352015-02-03 16:46:15 -0800734 private IntentBatchPreprocess(Collection<IntentData> ops, long endTime) {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800735 this.ops = checkNotNull(ops);
736 this.endTime = endTime;
737 }
738
Brian O'Connorb499b352015-02-03 16:46:15 -0800739 public IntentBatchPreprocess(Collection<IntentData> ops) {
740 this(ops, System.currentTimeMillis() + ops.size() * TIMEOUT_PER_OP);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800741 }
742
743 // FIXME compute reasonable timeouts
744 protected long calculateTimeoutLimit() {
Brian O'Connorb499b352015-02-03 16:46:15 -0800745 return System.currentTimeMillis() + ops.size() * TIMEOUT_PER_OP;
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800746 }
747
748 @Override
749 public void run() {
750 try {
751 // this should only be called on the first iteration
752 // note: this a "expensive", so it is not done in the constructor
753
754 // - creates per Intent installation context (IntentUpdate)
755 // - write Intents to store
756 // - process (compile, install, etc.) each Intents
757 // - generate FlowRuleBatch for this phase
758 // build IntentUpdates
759 List<IntentUpdate> updates = createIntentUpdates();
760
761 // Write batch information
762 BatchWrite batchWrite = createBatchWrite(updates);
Sho SHIMIZU9ea34532015-01-28 12:28:00 -0800763 store.batchWrite(batchWrite);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800764
765 new IntentBatchApplyFirst(ops, processIntentUpdates(updates), endTime, 0, null).run();
766 } catch (Exception e) {
767 log.error("Error submitting batches:", e);
768 // FIXME incomplete Intents should be cleaned up
769 // (transition to FAILED, etc.)
770
771 // TODO: remove duplicate due to inlining
772 // the batch has failed
773 // TODO: maybe we should do more?
774 log.error("Walk the plank, matey...");
Brian O'Connorb499b352015-02-03 16:46:15 -0800775 //FIXME
776// batchService.removeIntentOperations(ops);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800777 }
778 }
779
780 private List<IntentUpdate> createIntentUpdates() {
Brian O'Connorb499b352015-02-03 16:46:15 -0800781 return ops.stream()
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800782 .map(IntentManager.this::createIntentUpdate)
783 .collect(Collectors.toList());
784 }
785
786 private BatchWrite createBatchWrite(List<IntentUpdate> updates) {
787 BatchWrite batchWrite = BatchWrite.newInstance();
788 updates.forEach(update -> update.writeBeforeExecution(batchWrite));
789 return batchWrite;
790 }
791
792 private List<CompletedIntentUpdate> processIntentUpdates(List<IntentUpdate> updates) {
793 // start processing each Intents
794 List<CompletedIntentUpdate> completed = new ArrayList<>();
795 for (IntentUpdate update : updates) {
796 Optional<IntentUpdate> phase = Optional.of(update);
797 IntentUpdate previous = update;
798 while (true) {
799 if (!phase.isPresent()) {
800 // FIXME: not type safe cast
801 completed.add((CompletedIntentUpdate) previous);
802 break;
803 }
804 previous = phase.get();
805 phase = previous.execute();
806 }
807 }
808
809 return completed;
810 }
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800811 }
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800812
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800813 // TODO: better naming
814 private class IntentBatchApplyFirst extends IntentBatchPreprocess {
815
816 protected final List<CompletedIntentUpdate> intentUpdates;
817 protected final int installAttempt;
818 protected Future<CompletedBatchOperation> future;
819
Brian O'Connorb499b352015-02-03 16:46:15 -0800820 IntentBatchApplyFirst(Collection<IntentData> operations, List<CompletedIntentUpdate> intentUpdates,
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800821 long endTime, int installAttempt, Future<CompletedBatchOperation> future) {
822 super(operations, endTime);
823 this.intentUpdates = ImmutableList.copyOf(intentUpdates);
824 this.future = future;
825 this.installAttempt = installAttempt;
826 }
827
828 @Override
829 public void run() {
830 Future<CompletedBatchOperation> future = applyNextBatch(intentUpdates);
831 new IntentBatchProcessFutures(ops, intentUpdates, endTime, installAttempt, future).run();
Brian O'Connorcb900f42014-10-07 21:55:33 -0700832 }
833
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700834 /**
Brian O'Connor427a1762014-11-19 18:40:32 -0800835 * Builds and applies the next batch, and returns the future.
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700836 *
837 * @return Future for next batch
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700838 */
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800839 protected Future<CompletedBatchOperation> applyNextBatch(List<CompletedIntentUpdate> updates) {
Brian O'Connor427a1762014-11-19 18:40:32 -0800840 //TODO test this. (also, maybe save this batch)
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800841
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800842 FlowRuleBatchOperation batch = createFlowRuleBatchOperation(updates);
Ray Milkey93508c22014-12-02 11:35:56 -0800843 if (batch.size() > 0) {
844 //FIXME apply batch might throw an exception
845 return flowRuleService.applyBatch(batch);
846 } else {
847 // there are no flow rule batches; finalize the intent update
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800848 BatchWrite batchWrite = createFinalizedBatchWrite(updates);
849
Sho SHIMIZU9ea34532015-01-28 12:28:00 -0800850 store.batchWrite(batchWrite);
Ray Milkey93508c22014-12-02 11:35:56 -0800851 return null;
852 }
853 }
854
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800855 private FlowRuleBatchOperation createFlowRuleBatchOperation(List<CompletedIntentUpdate> intentUpdates) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800856 FlowRuleBatchOperation batch = new FlowRuleBatchOperation(Collections.emptyList(), null, 0);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800857 for (CompletedIntentUpdate update : intentUpdates) {
858 FlowRuleBatchOperation currentBatch = update.currentBatch();
859 if (currentBatch != null) {
860 batch.addAll(currentBatch);
861 }
862 }
863 return batch;
864 }
865
866 private BatchWrite createFinalizedBatchWrite(List<CompletedIntentUpdate> intentUpdates) {
867 BatchWrite batchWrite = BatchWrite.newInstance();
868 for (CompletedIntentUpdate update : intentUpdates) {
869 update.writeAfterExecution(batchWrite);
870 }
871 return batchWrite;
872 }
873
874 protected void abandonShip() {
875 // the batch has failed
876 // TODO: maybe we should do more?
877 log.error("Walk the plank, matey...");
878 future = null;
Brian O'Connorb499b352015-02-03 16:46:15 -0800879 //FIXME
880// batchService.removeIntentOperations(ops);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800881 }
882 }
883
884 // TODO: better naming
885 private class IntentBatchProcessFutures extends IntentBatchApplyFirst {
886
Brian O'Connorb499b352015-02-03 16:46:15 -0800887 IntentBatchProcessFutures(Collection<IntentData> operations, List<CompletedIntentUpdate> intentUpdates,
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800888 long endTime, int installAttempt, Future<CompletedBatchOperation> future) {
889 super(operations, intentUpdates, endTime, installAttempt, future);
890 }
891
892 @Override
893 public void run() {
894 try {
895 // - peek if current FlowRuleBatch is complete
896 // -- If complete OK:
897 // step each IntentUpdate forward
898 // If phase left: generate next FlowRuleBatch
899 // If no more phase: write parking states
900 // -- If complete FAIL:
901 // Intent which failed: transition Intent to FAILED
902 // Other Intents: resubmit same FlowRuleBatch for this phase
903 Future<CompletedBatchOperation> future = processFutures();
904 if (future == null) {
905 // there are no outstanding batches; we are done
Brian O'Connorb499b352015-02-03 16:46:15 -0800906 //FIXME
907 return; //?
908// batchService.removeIntentOperations(ops);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800909 } else if (System.currentTimeMillis() > endTime) {
910 // - cancel current FlowRuleBatch and resubmit again
911 retry();
912 } else {
913 // we are not done yet, yield the thread by resubmitting ourselves
914 executor.submit(new IntentBatchProcessFutures(ops, intentUpdates, endTime, installAttempt, future));
915 }
916 } catch (Exception e) {
917 log.error("Error submitting batches:", e);
918 // FIXME incomplete Intents should be cleaned up
919 // (transition to FAILED, etc.)
920 abandonShip();
921 }
922 }
923
924 /**
925 * Iterate through the pending futures, and remove them when they have completed.
926 */
927 private Future<CompletedBatchOperation> processFutures() {
928 try {
929 CompletedBatchOperation completed = future.get(100, TimeUnit.NANOSECONDS);
930 updateBatches(completed);
931 return applyNextBatch(intentUpdates);
932 } catch (TimeoutException | InterruptedException te) {
933 log.trace("Installation of intents are still pending: {}", ops);
934 return future;
935 } catch (ExecutionException e) {
936 log.warn("Execution of batch failed: {}", ops, e);
937 abandonShip();
938 return future;
939 }
940 }
941
Ray Milkey93508c22014-12-02 11:35:56 -0800942 private void updateBatches(CompletedBatchOperation completed) {
943 if (completed.isSuccess()) {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800944 for (CompletedIntentUpdate update : intentUpdates) {
Ray Milkey93508c22014-12-02 11:35:56 -0800945 update.batchSuccess();
946 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700947 } else {
Brian O'Connor427a1762014-11-19 18:40:32 -0800948 // entire batch has been reverted...
Ray Milkey93508c22014-12-02 11:35:56 -0800949 log.debug("Failed items: {}", completed.failedItems());
950 log.debug("Failed ids: {}", completed.failedIds());
Brian O'Connor427a1762014-11-19 18:40:32 -0800951
952 for (Long id : completed.failedIds()) {
953 IntentId targetId = IntentId.valueOf(id);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800954 for (CompletedIntentUpdate update : intentUpdates) {
955 for (Intent intent : update.allInstallables()) {
Brian O'Connor427a1762014-11-19 18:40:32 -0800956 if (intent.id().equals(targetId)) {
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800957 update.batchFailed();
Brian O'Connor427a1762014-11-19 18:40:32 -0800958 break;
959 }
960 }
961 }
962 // don't increment the non-failed items, as they have been reverted.
963 }
964 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700965 }
966
Brian O'Connor427a1762014-11-19 18:40:32 -0800967 private void retry() {
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800968 log.debug("Execution timed out, retrying.");
Brian O'Connor427a1762014-11-19 18:40:32 -0800969 if (future.cancel(true)) { // cancel success; batch is reverted
970 // reset the timer
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800971 long timeLimit = calculateTimeoutLimit();
972 int attempts = installAttempt + 1;
973 if (attempts == MAX_ATTEMPTS) {
Brian O'Connor427a1762014-11-19 18:40:32 -0800974 log.warn("Install request timed out: {}", ops);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800975 for (CompletedIntentUpdate update : intentUpdates) {
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800976 update.batchFailed();
Brian O'Connor427a1762014-11-19 18:40:32 -0800977 }
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800978 } else if (attempts > MAX_ATTEMPTS) {
Ray Milkey93508c22014-12-02 11:35:56 -0800979 abandonShip();
980 return;
Brian O'Connor427a1762014-11-19 18:40:32 -0800981 } // else just resubmit the work
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800982 Future<CompletedBatchOperation> future = applyNextBatch(intentUpdates);
983 executor.submit(new IntentBatchProcessFutures(ops, intentUpdates, timeLimit, attempts, future));
Brian O'Connor427a1762014-11-19 18:40:32 -0800984 } else {
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800985 log.error("Cancelling FlowRuleBatch failed.");
Brian O'Connor427a1762014-11-19 18:40:32 -0800986 // FIXME
987 // cancel failed... batch is broken; shouldn't happen!
988 // we could manually reverse everything
989 // ... or just core dump and send email to Ali
Ray Milkey93508c22014-12-02 11:35:56 -0800990 abandonShip();
Brian O'Connor427a1762014-11-19 18:40:32 -0800991 }
992 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700993 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700994
995 private class InternalBatchDelegate implements IntentBatchDelegate {
996 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800997 public void execute(Collection<IntentData> operations) {
998 log.info("Execute {} operation(s).", operations.size());
999 log.debug("Execute operations: {}", operations);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -08001000 executor.execute(new IntentBatchPreprocess(operations));
Brian O'Connorfa81eae2014-10-30 13:20:05 -07001001 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -07001002 }
Brian O'Connor66630c82014-10-02 21:08:19 -07001003}