blob: bc7e4059bb1ae34f7b60635d8ed35fa889a0b02b [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net.intent.impl;
Brian O'Connor66630c82014-10-02 21:08:19 -070017
Brian O'Connorf0c5a052015-04-27 00:34:53 -070018import com.google.common.collect.ImmutableList;
Brian O'Connor66630c82014-10-02 21:08:19 -070019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
Brian O'Connorabafb502014-12-02 22:26:20 -080025import org.onosproject.core.CoreService;
26import org.onosproject.core.IdGenerator;
27import org.onosproject.event.AbstractListenerRegistry;
28import org.onosproject.event.EventDeliveryService;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080029import org.onosproject.net.flow.FlowRule;
Brian O'Connor0e271dc2015-02-04 18:20:25 -080030import org.onosproject.net.flow.FlowRuleOperations;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080031import org.onosproject.net.flow.FlowRuleOperationsContext;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.net.flow.FlowRuleService;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080033import org.onosproject.net.intent.FlowRuleIntent;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.net.intent.Intent;
35import org.onosproject.net.intent.IntentBatchDelegate;
Brian O'Connorabafb502014-12-02 22:26:20 -080036import org.onosproject.net.intent.IntentCompiler;
Brian O'Connorcff03322015-02-03 15:28:59 -080037import org.onosproject.net.intent.IntentData;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.net.intent.IntentEvent;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.intent.IntentExtensionService;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.net.intent.IntentListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080041import org.onosproject.net.intent.IntentService;
42import org.onosproject.net.intent.IntentState;
43import org.onosproject.net.intent.IntentStore;
Brian O'Connorabafb502014-12-02 22:26:20 -080044import org.onosproject.net.intent.IntentStoreDelegate;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080045import org.onosproject.net.intent.Key;
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -080046import org.onosproject.net.intent.impl.phase.FinalIntentProcessPhase;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080047import org.onosproject.net.intent.impl.phase.IntentProcessPhase;
Sho SHIMIZU662c3db2015-02-23 16:59:01 -080048import org.onosproject.net.intent.impl.phase.IntentWorker;
Brian O'Connor66630c82014-10-02 21:08:19 -070049import org.slf4j.Logger;
50
Brian O'Connorf0c5a052015-04-27 00:34:53 -070051import java.util.Collection;
52import java.util.EnumSet;
53import java.util.List;
54import java.util.Map;
55import java.util.Optional;
56import java.util.concurrent.ExecutionException;
57import java.util.concurrent.ExecutorService;
58import java.util.concurrent.Future;
59import java.util.stream.Collectors;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070060
Brian O'Connorfa81eae2014-10-30 13:20:05 -070061import static com.google.common.base.Preconditions.checkNotNull;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080062import static java.util.concurrent.Executors.newFixedThreadPool;
Brian O'Connordb15b042015-02-04 14:59:28 -080063import static java.util.concurrent.Executors.newSingleThreadExecutor;
Brian O'Connorbdc7f002015-02-18 20:49:41 -080064import static org.onlab.util.Tools.groupedThreads;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070065import static org.onosproject.net.intent.IntentState.*;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080066import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070067import static org.slf4j.LoggerFactory.getLogger;
Brian O'Connor66630c82014-10-02 21:08:19 -070068
69/**
70 * An implementation of Intent Manager.
71 */
72@Component(immediate = true)
73@Service
74public class IntentManager
75 implements IntentService, IntentExtensionService {
Sho SHIMIZU8b5051d2014-11-05 11:24:13 -080076 private static final Logger log = getLogger(IntentManager.class);
Brian O'Connor66630c82014-10-02 21:08:19 -070077
78 public static final String INTENT_NULL = "Intent cannot be null";
Ray Milkeyf9af43c2015-02-09 16:45:48 -080079 public static final String INTENT_ID_NULL = "Intent key cannot be null";
Brian O'Connor66630c82014-10-02 21:08:19 -070080
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080081 private static final int NUM_THREADS = 12;
82
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080083 private static final EnumSet<IntentState> RECOMPILE
84 = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080085
Brian O'Connor66630c82014-10-02 21:08:19 -070086 private final AbstractListenerRegistry<IntentEvent, IntentListener>
tom95329eb2014-10-06 08:40:06 -070087 listenerRegistry = new AbstractListenerRegistry<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070088
Brian O'Connor520c0522014-11-23 23:50:47 -080089 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected CoreService coreService;
Brian O'Connor66630c82014-10-02 21:08:19 -070091
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected IntentStore store;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -070096 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -070097
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Brian O'Connor66630c82014-10-02 21:08:19 -070099 protected EventDeliveryService eventDispatcher;
100
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700101 @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'Connor520c0522014-11-23 23:50:47 -0800104
Brian O'Connordb15b042015-02-04 14:59:28 -0800105 private ExecutorService batchExecutor;
106 private ExecutorService workerExecutor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800107
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800108 private final CompilerRegistry compilerRegistry = new CompilerRegistry();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800109 private final InternalIntentProcessor processor = new InternalIntentProcessor();
Brian O'Connor520c0522014-11-23 23:50:47 -0800110 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
111 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
112 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
113 private IdGenerator idGenerator;
114
Brian O'Connorb499b352015-02-03 16:46:15 -0800115 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800116
Brian O'Connor66630c82014-10-02 21:08:19 -0700117 @Activate
118 public void activate() {
119 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700120 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700121 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorbdc7f002015-02-18 20:49:41 -0800122 batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch"));
123 workerExecutor = newFixedThreadPool(NUM_THREADS, groupedThreads("onos/intent", "worker-%d"));
Brian O'Connor520c0522014-11-23 23:50:47 -0800124 idGenerator = coreService.getIdGenerator("intent-ids");
125 Intent.bindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700126 log.info("Started");
127 }
128
129 @Deactivate
130 public void deactivate() {
131 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700132 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700133 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connordb15b042015-02-04 14:59:28 -0800134 batchExecutor.shutdown();
Brian O'Connor3c58e962015-04-28 23:21:51 -0700135 workerExecutor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800136 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700137 log.info("Stopped");
138 }
139
140 @Override
141 public void submit(Intent intent) {
142 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) {
149 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800150 IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800151 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700152 }
153
Brian O'Connor66630c82014-10-02 21:08:19 -0700154 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700155 public void purge(Intent intent) {
156 checkNotNull(intent, INTENT_NULL);
157 IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null);
158 store.addPending(data);
159 }
160
161 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800162 public Intent getIntent(Key key) {
163 return store.getIntent(key);
164 }
165
166 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700167 public Iterable<Intent> getIntents() {
168 return store.getIntents();
169 }
170
171 @Override
172 public long getIntentCount() {
173 return store.getIntentCount();
174 }
175
176 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800177 public IntentState getIntentState(Key intentKey) {
178 checkNotNull(intentKey, INTENT_ID_NULL);
179 return store.getIntentState(intentKey);
Brian O'Connor66630c82014-10-02 21:08:19 -0700180 }
181
182 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800183 public List<Intent> getInstallableIntents(Key intentKey) {
184 checkNotNull(intentKey, INTENT_ID_NULL);
185 return store.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700186 }
187
188 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800189 public boolean isLocal(Key intentKey) {
190 return store.isMaster(intentKey);
191 }
192
193 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700194 public void addListener(IntentListener listener) {
195 listenerRegistry.addListener(listener);
196 }
197
198 @Override
199 public void removeListener(IntentListener listener) {
200 listenerRegistry.removeListener(listener);
201 }
202
203 @Override
204 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800205 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700206 }
207
208 @Override
209 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800210 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700211 }
212
213 @Override
214 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800215 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700216 }
217
218 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800219 public Iterable<Intent> getPending() {
220 return store.getPending();
221 }
222
Brian O'Connor66630c82014-10-02 21:08:19 -0700223 // Store delegate to re-post events emitted from the store.
224 private class InternalStoreDelegate implements IntentStoreDelegate {
225 @Override
226 public void notify(IntentEvent event) {
tom85258ee2014-10-07 00:10:02 -0700227 eventDispatcher.post(event);
Brian O'Connor66630c82014-10-02 21:08:19 -0700228 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800229
230 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800231 public void process(IntentData data) {
232 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800233 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700234 }
235
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800236 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800237 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800238 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800239 for (Key key : intentKeys) {
240 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800241 if (intent == null) {
242 continue;
243 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800244 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800245 }
246
247 if (compileAllFailed) {
248 // If required, compile all currently failed intents.
249 for (Intent intent : getIntents()) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800250 IntentState state = getIntentState(intent.key());
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800251 if (RECOMPILE.contains(state)) {
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800252 if (state == WITHDRAW_REQ) {
Brian O'Connor03406a42015-02-03 17:28:57 -0800253 withdraw(intent);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800254 } else {
Brian O'Connor03406a42015-02-03 17:28:57 -0800255 submit(intent);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800256 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800257 }
258 }
259 }
260
Brian O'Connorb499b352015-02-03 16:46:15 -0800261 //FIXME
262// for (ApplicationId appId : batches.keySet()) {
263// if (batchService.isLocalLeader(appId)) {
264// execute(batches.get(appId).build());
265// }
266// }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800267 }
268
tom95329eb2014-10-06 08:40:06 -0700269 // Topology change delegate
270 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
271 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800272 public void triggerCompile(Iterable<Key> intentKeys,
tom85258ee2014-10-07 00:10:02 -0700273 boolean compileAllFailed) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800274 buildAndSubmitBatches(intentKeys, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700275 }
tom95329eb2014-10-06 08:40:06 -0700276 }
tom85258ee2014-10-07 00:10:02 -0700277
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800278 private Future<FinalIntentProcessPhase> submitIntentData(IntentData data) {
Sho SHIMIZU0cb6fe62015-02-23 16:39:57 -0800279 IntentData current = store.getIntentData(data.key());
Sho SHIMIZUce49b602015-02-23 19:15:49 -0800280 IntentProcessPhase initial = newInitialPhase(processor, data, current);
281 return workerExecutor.submit(new IntentWorker(initial));
Sho SHIMIZU8d9d1362015-02-04 12:28:15 -0800282 }
283
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800284 private class IntentBatchProcess implements Runnable {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800285
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800286 protected final Collection<IntentData> data;
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800287
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800288 IntentBatchProcess(Collection<IntentData> data) {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800289 this.data = checkNotNull(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800290 }
291
292 @Override
293 public void run() {
294 try {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800295 /*
296 1. wrap each intentdata in a runnable and submit
297 2. wait for completion of all the work
298 3. accumulate results and submit batch write of IntentData to store
299 (we can also try to update these individually)
300 */
301 submitUpdates(waitForFutures(createIntentUpdates()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800302 } catch (Exception e) {
303 log.error("Error submitting batches:", e);
304 // FIXME incomplete Intents should be cleaned up
305 // (transition to FAILED, etc.)
306
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800307 // the batch has failed
308 // TODO: maybe we should do more?
309 log.error("Walk the plank, matey...");
Brian O'Connorb499b352015-02-03 16:46:15 -0800310 //FIXME
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800311// batchService.removeIntentOperations(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800312 }
Brian O'Connor3c4b00d2015-02-22 20:42:26 -0800313 accumulator.ready();
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800314 }
315
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800316 private List<Future<FinalIntentProcessPhase>> createIntentUpdates() {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800317 return data.stream()
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800318 .map(IntentManager.this::submitIntentData)
319 .collect(Collectors.toList());
320 }
321
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800322 private List<FinalIntentProcessPhase> waitForFutures(List<Future<FinalIntentProcessPhase>> futures) {
323 ImmutableList.Builder<FinalIntentProcessPhase> updateBuilder = ImmutableList.builder();
324 for (Future<FinalIntentProcessPhase> future : futures) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800325 try {
326 updateBuilder.add(future.get());
327 } catch (InterruptedException | ExecutionException e) {
328 //FIXME
329 log.warn("Future failed: {}", e);
330 }
331 }
332 return updateBuilder.build();
333 }
334
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800335 private void submitUpdates(List<FinalIntentProcessPhase> updates) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800336 store.batchWrite(updates.stream()
Brian O'Connorb5dcc512015-03-24 17:28:00 -0700337 .map(FinalIntentProcessPhase::data)
338 .collect(Collectors.toList()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800339 }
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800340 }
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800341
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700342 private class InternalBatchDelegate implements IntentBatchDelegate {
343 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800344 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800345 log.debug("Execute {} operation(s).", operations.size());
346 log.trace("Execute operations: {}", operations);
Sho SHIMIZU94b03b12015-04-10 14:53:13 -0700347
348 // batchExecutor is single-threaded, so only one batch is in flight at a time
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800349 batchExecutor.execute(new IntentBatchProcess(operations));
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700350 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700351 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800352
353 private class InternalIntentProcessor implements IntentProcessor {
354 @Override
355 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
356 return compilerRegistry.compile(intent, previousInstallables);
357 }
358
359 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700360 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700361 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800362 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700363 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800364
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700365 private enum Direction {
366 ADD,
367 REMOVE
368 }
369
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700370 private void applyIntentData(Optional<IntentData> intentData,
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700371 FlowRuleOperations.Builder builder,
372 Direction direction) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700373 if (!intentData.isPresent()) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700374 return;
375 }
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700376 IntentData data = intentData.get();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700377
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700378 List<Intent> intentsToApply = data.installables();
379 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
380 throw new IllegalStateException("installable intents must be FlowRuleIntent");
381 }
382
383 if (direction == Direction.ADD) {
384 trackerService.addTrackedResources(data.key(), data.intent().resources());
385 intentsToApply.forEach(installable ->
386 trackerService.addTrackedResources(data.key(), installable.resources()));
387 } else {
388 trackerService.removeTrackedResources(data.key(), data.intent().resources());
389 intentsToApply.forEach(installable ->
390 trackerService.removeTrackedResources(data.intent().key(),
391 installable.resources()));
392 }
393
394 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
395 builder.newStage();
396
397 List<Collection<FlowRule>> stages = intentsToApply.stream()
398 .map(x -> (FlowRuleIntent) x)
399 .map(FlowRuleIntent::flowRules)
400 .collect(Collectors.toList());
401
402 for (Collection<FlowRule> rules : stages) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700403 if (direction == Direction.ADD) {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700404 rules.forEach(builder::add);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700405 } else {
Sho SHIMIZUfcf861a2015-04-10 14:37:08 -0700406 rules.forEach(builder::remove);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700407 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800408 }
409
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800410 }
411
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700412 private void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800413 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800414
415 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700416 applyIntentData(toUninstall, builder, Direction.REMOVE);
417 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800418
419 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
420 @Override
421 public void onSuccess(FlowRuleOperations ops) {
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700422 if (toInstall.isPresent()) {
423 IntentData installData = toInstall.get();
424 log.debug("Completed installing: {}", installData.key());
425 installData.setState(INSTALLED);
426 store.write(installData);
427 } else if (toUninstall.isPresent()) {
428 IntentData uninstallData = toUninstall.get();
429 log.debug("Completed withdrawing: {}", uninstallData.key());
430 switch (uninstallData.request()) {
431 case INSTALL_REQ:
432 uninstallData.setState(FAILED);
433 break;
434 case WITHDRAW_REQ:
435 default: //TODO "default" case should not happen
436 uninstallData.setState(WITHDRAWN);
437 break;
438 }
439 store.write(uninstallData);
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700440 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800441 }
442
443 @Override
444 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700445 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700446 if (toInstall.isPresent()) {
447 IntentData installData = toInstall.get();
448 log.warn("Failed installation: {} {} on {}",
449 installData.key(), installData.intent(), ops);
450 installData.setState(CORRUPT);
451 store.write(installData);
452 }
Sho SHIMIZUd4936252015-04-10 15:03:57 -0700453 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700454 if (toUninstall.isPresent()) {
455 IntentData uninstallData = toUninstall.get();
456 log.warn("Failed withdrawal: {} {} on {}",
457 uninstallData.key(), uninstallData.intent(), ops);
458 uninstallData.setState(CORRUPT);
459 store.write(uninstallData);
460 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800461 }
462 });
463
464 flowRuleService.apply(operations);
465 }
466
Brian O'Connor66630c82014-10-02 21:08:19 -0700467}