blob: 610b030294d4d3055b69d9848b49e85375ec062e [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
Ray Milkeyfd7931d2015-03-30 13:58:38 -070018import java.util.Collection;
19import java.util.EnumSet;
20import java.util.List;
21import java.util.Map;
22import java.util.concurrent.ExecutionException;
23import java.util.concurrent.ExecutorService;
24import java.util.concurrent.Future;
25import java.util.stream.Collectors;
26
Brian O'Connor66630c82014-10-02 21:08:19 -070027import org.apache.felix.scr.annotations.Activate;
28import org.apache.felix.scr.annotations.Component;
29import org.apache.felix.scr.annotations.Deactivate;
30import org.apache.felix.scr.annotations.Reference;
31import org.apache.felix.scr.annotations.ReferenceCardinality;
32import org.apache.felix.scr.annotations.Service;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.core.CoreService;
34import org.onosproject.core.IdGenerator;
35import org.onosproject.event.AbstractListenerRegistry;
36import org.onosproject.event.EventDeliveryService;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080037import org.onosproject.net.flow.FlowRule;
Brian O'Connor0e271dc2015-02-04 18:20:25 -080038import org.onosproject.net.flow.FlowRuleOperations;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080039import org.onosproject.net.flow.FlowRuleOperationsContext;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.net.flow.FlowRuleService;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080041import org.onosproject.net.intent.FlowRuleIntent;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.net.intent.Intent;
43import org.onosproject.net.intent.IntentBatchDelegate;
Brian O'Connorabafb502014-12-02 22:26:20 -080044import org.onosproject.net.intent.IntentCompiler;
Brian O'Connorcff03322015-02-03 15:28:59 -080045import org.onosproject.net.intent.IntentData;
Brian O'Connorabafb502014-12-02 22:26:20 -080046import org.onosproject.net.intent.IntentEvent;
Brian O'Connorabafb502014-12-02 22:26:20 -080047import org.onosproject.net.intent.IntentExtensionService;
Brian O'Connorabafb502014-12-02 22:26:20 -080048import org.onosproject.net.intent.IntentListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080049import org.onosproject.net.intent.IntentService;
50import org.onosproject.net.intent.IntentState;
51import org.onosproject.net.intent.IntentStore;
Brian O'Connorabafb502014-12-02 22:26:20 -080052import org.onosproject.net.intent.IntentStoreDelegate;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080053import org.onosproject.net.intent.Key;
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -080054import org.onosproject.net.intent.impl.phase.FinalIntentProcessPhase;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080055import org.onosproject.net.intent.impl.phase.IntentProcessPhase;
Sho SHIMIZU662c3db2015-02-23 16:59:01 -080056import org.onosproject.net.intent.impl.phase.IntentWorker;
Brian O'Connor66630c82014-10-02 21:08:19 -070057import org.slf4j.Logger;
58
Ray Milkeyfd7931d2015-03-30 13:58:38 -070059import com.google.common.collect.ImmutableList;
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;
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -080065import static org.onosproject.net.intent.IntentState.FAILED;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080066import static org.onosproject.net.intent.IntentState.INSTALLED;
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -080067import static org.onosproject.net.intent.IntentState.INSTALL_REQ;
Sho SHIMIZUee2aa652015-02-25 18:56:43 -080068import static org.onosproject.net.intent.IntentState.WITHDRAWN;
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -080069import static org.onosproject.net.intent.IntentState.WITHDRAW_REQ;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080070import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070071import static org.slf4j.LoggerFactory.getLogger;
Brian O'Connor66630c82014-10-02 21:08:19 -070072
73/**
74 * An implementation of Intent Manager.
75 */
76@Component(immediate = true)
77@Service
78public class IntentManager
79 implements IntentService, IntentExtensionService {
Sho SHIMIZU8b5051d2014-11-05 11:24:13 -080080 private static final Logger log = getLogger(IntentManager.class);
Brian O'Connor66630c82014-10-02 21:08:19 -070081
82 public static final String INTENT_NULL = "Intent cannot be null";
Ray Milkeyf9af43c2015-02-09 16:45:48 -080083 public static final String INTENT_ID_NULL = "Intent key cannot be null";
Brian O'Connor66630c82014-10-02 21:08:19 -070084
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080085 private static final int NUM_THREADS = 12;
86
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080087 private static final EnumSet<IntentState> RECOMPILE
88 = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080089
Brian O'Connor66630c82014-10-02 21:08:19 -070090 private final AbstractListenerRegistry<IntentEvent, IntentListener>
tom95329eb2014-10-06 08:40:06 -070091 listenerRegistry = new AbstractListenerRegistry<>();
Brian O'Connor66630c82014-10-02 21:08:19 -070092
Brian O'Connor520c0522014-11-23 23:50:47 -080093 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected CoreService coreService;
Brian O'Connor66630c82014-10-02 21:08:19 -070095
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected IntentStore store;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -0700100 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -0700101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Brian O'Connor66630c82014-10-02 21:08:19 -0700103 protected EventDeliveryService eventDispatcher;
104
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZU214ac322015-02-23 19:30:15 -0800106 protected FlowRuleService flowRuleService;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700107
Brian O'Connor520c0522014-11-23 23:50:47 -0800108
Brian O'Connordb15b042015-02-04 14:59:28 -0800109 private ExecutorService batchExecutor;
110 private ExecutorService workerExecutor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800111
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800112 private final CompilerRegistry compilerRegistry = new CompilerRegistry();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800113 private final InternalIntentProcessor processor = new InternalIntentProcessor();
Brian O'Connor520c0522014-11-23 23:50:47 -0800114 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
115 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
116 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
117 private IdGenerator idGenerator;
118
Brian O'Connorb499b352015-02-03 16:46:15 -0800119 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800120
Brian O'Connor66630c82014-10-02 21:08:19 -0700121 @Activate
122 public void activate() {
123 store.setDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700124 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700125 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
Brian O'Connorbdc7f002015-02-18 20:49:41 -0800126 batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch"));
127 workerExecutor = newFixedThreadPool(NUM_THREADS, groupedThreads("onos/intent", "worker-%d"));
Brian O'Connor520c0522014-11-23 23:50:47 -0800128 idGenerator = coreService.getIdGenerator("intent-ids");
129 Intent.bindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700130 log.info("Started");
131 }
132
133 @Deactivate
134 public void deactivate() {
135 store.unsetDelegate(delegate);
tom95329eb2014-10-06 08:40:06 -0700136 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700137 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connordb15b042015-02-04 14:59:28 -0800138 batchExecutor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800139 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700140 log.info("Stopped");
141 }
142
143 @Override
144 public void submit(Intent intent) {
145 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800146 IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800147 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700148 }
149
150 @Override
151 public void withdraw(Intent intent) {
152 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800153 IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800154 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700155 }
156
Brian O'Connor66630c82014-10-02 21:08:19 -0700157 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700158 public void purge(Intent intent) {
159 checkNotNull(intent, INTENT_NULL);
160 IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null);
161 store.addPending(data);
162 }
163
164 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800165 public Intent getIntent(Key key) {
166 return store.getIntent(key);
167 }
168
169 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700170 public Iterable<Intent> getIntents() {
171 return store.getIntents();
172 }
173
174 @Override
175 public long getIntentCount() {
176 return store.getIntentCount();
177 }
178
179 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800180 public IntentState getIntentState(Key intentKey) {
181 checkNotNull(intentKey, INTENT_ID_NULL);
182 return store.getIntentState(intentKey);
Brian O'Connor66630c82014-10-02 21:08:19 -0700183 }
184
185 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800186 public List<Intent> getInstallableIntents(Key intentKey) {
187 checkNotNull(intentKey, INTENT_ID_NULL);
188 return store.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700189 }
190
191 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800192 public boolean isLocal(Key intentKey) {
193 return store.isMaster(intentKey);
194 }
195
196 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700197 public void addListener(IntentListener listener) {
198 listenerRegistry.addListener(listener);
199 }
200
201 @Override
202 public void removeListener(IntentListener listener) {
203 listenerRegistry.removeListener(listener);
204 }
205
206 @Override
207 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800208 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700209 }
210
211 @Override
212 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800213 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700214 }
215
216 @Override
217 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800218 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700219 }
220
221 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800222 public Iterable<Intent> getPending() {
223 return store.getPending();
224 }
225
Brian O'Connor66630c82014-10-02 21:08:19 -0700226 // Store delegate to re-post events emitted from the store.
227 private class InternalStoreDelegate implements IntentStoreDelegate {
228 @Override
229 public void notify(IntentEvent event) {
tom85258ee2014-10-07 00:10:02 -0700230 eventDispatcher.post(event);
Brian O'Connor66630c82014-10-02 21:08:19 -0700231 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800232
233 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800234 public void process(IntentData data) {
235 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800236 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700237 }
238
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800239 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800240 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800241 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800242 for (Key key : intentKeys) {
243 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800244 if (intent == null) {
245 continue;
246 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800247 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800248 }
249
250 if (compileAllFailed) {
251 // If required, compile all currently failed intents.
252 for (Intent intent : getIntents()) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800253 IntentState state = getIntentState(intent.key());
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800254 if (RECOMPILE.contains(state)) {
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800255 if (state == WITHDRAW_REQ) {
Brian O'Connor03406a42015-02-03 17:28:57 -0800256 withdraw(intent);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800257 } else {
Brian O'Connor03406a42015-02-03 17:28:57 -0800258 submit(intent);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800259 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800260 }
261 }
262 }
263
Brian O'Connorb499b352015-02-03 16:46:15 -0800264 //FIXME
265// for (ApplicationId appId : batches.keySet()) {
266// if (batchService.isLocalLeader(appId)) {
267// execute(batches.get(appId).build());
268// }
269// }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800270 }
271
tom95329eb2014-10-06 08:40:06 -0700272 // Topology change delegate
273 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
274 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800275 public void triggerCompile(Iterable<Key> intentKeys,
tom85258ee2014-10-07 00:10:02 -0700276 boolean compileAllFailed) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800277 buildAndSubmitBatches(intentKeys, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700278 }
tom95329eb2014-10-06 08:40:06 -0700279 }
tom85258ee2014-10-07 00:10:02 -0700280
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800281 private Future<FinalIntentProcessPhase> submitIntentData(IntentData data) {
Sho SHIMIZU0cb6fe62015-02-23 16:39:57 -0800282 IntentData current = store.getIntentData(data.key());
Sho SHIMIZUce49b602015-02-23 19:15:49 -0800283 IntentProcessPhase initial = newInitialPhase(processor, data, current);
284 return workerExecutor.submit(new IntentWorker(initial));
Sho SHIMIZU8d9d1362015-02-04 12:28:15 -0800285 }
286
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800287 private class IntentBatchProcess implements Runnable {
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800288
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800289 protected final Collection<IntentData> data;
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800290
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800291 IntentBatchProcess(Collection<IntentData> data) {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800292 this.data = checkNotNull(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800293 }
294
295 @Override
296 public void run() {
297 try {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800298 /*
299 1. wrap each intentdata in a runnable and submit
300 2. wait for completion of all the work
301 3. accumulate results and submit batch write of IntentData to store
302 (we can also try to update these individually)
303 */
304 submitUpdates(waitForFutures(createIntentUpdates()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800305 } catch (Exception e) {
306 log.error("Error submitting batches:", e);
307 // FIXME incomplete Intents should be cleaned up
308 // (transition to FAILED, etc.)
309
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800310 // the batch has failed
311 // TODO: maybe we should do more?
312 log.error("Walk the plank, matey...");
Brian O'Connorb499b352015-02-03 16:46:15 -0800313 //FIXME
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800314// batchService.removeIntentOperations(data);
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800315 }
Brian O'Connor3c4b00d2015-02-22 20:42:26 -0800316 accumulator.ready();
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800317 }
318
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800319 private List<Future<FinalIntentProcessPhase>> createIntentUpdates() {
Sho SHIMIZU5f281a42015-02-04 15:29:11 -0800320 return data.stream()
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800321 .map(IntentManager.this::submitIntentData)
322 .collect(Collectors.toList());
323 }
324
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800325 private List<FinalIntentProcessPhase> waitForFutures(List<Future<FinalIntentProcessPhase>> futures) {
326 ImmutableList.Builder<FinalIntentProcessPhase> updateBuilder = ImmutableList.builder();
327 for (Future<FinalIntentProcessPhase> future : futures) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800328 try {
329 updateBuilder.add(future.get());
330 } catch (InterruptedException | ExecutionException e) {
331 //FIXME
332 log.warn("Future failed: {}", e);
333 }
334 }
335 return updateBuilder.build();
336 }
337
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -0800338 private void submitUpdates(List<FinalIntentProcessPhase> updates) {
Brian O'Connor0e271dc2015-02-04 18:20:25 -0800339 store.batchWrite(updates.stream()
Brian O'Connorb5dcc512015-03-24 17:28:00 -0700340 .map(FinalIntentProcessPhase::data)
341 .collect(Collectors.toList()));
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800342 }
Sho SHIMIZUadf8c482014-12-12 18:23:29 -0800343 }
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -0800344
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700345 private class InternalBatchDelegate implements IntentBatchDelegate {
346 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800347 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800348 log.debug("Execute {} operation(s).", operations.size());
349 log.trace("Execute operations: {}", operations);
Sho SHIMIZUd42058e2015-02-23 16:16:20 -0800350 batchExecutor.execute(new IntentBatchProcess(operations));
Brian O'Connordb15b042015-02-04 14:59:28 -0800351 // TODO ensure that only one batch is in flight at a time
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700352 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700353 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800354
355 private class InternalIntentProcessor implements IntentProcessor {
356 @Override
357 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
358 return compilerRegistry.compile(intent, previousInstallables);
359 }
360
361 @Override
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700362 public void apply(IntentData toUninstall, IntentData toInstall) {
363 IntentManager.this.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800364 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700365 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800366
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700367 private enum Direction {
368 ADD,
369 REMOVE
370 }
371
372 private void applyIntentData(IntentData data,
373 FlowRuleOperations.Builder builder,
374 Direction direction) {
375 if (data != null) {
376 List<Intent> intentsToApply = data.installables();
377 if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) {
378 throw new IllegalStateException("installable intents must be FlowRuleIntent");
379 }
380
381 if (direction == Direction.ADD) {
382 trackerService.addTrackedResources(data.key(), data.intent().resources());
383 intentsToApply.forEach(installable ->
384 trackerService.addTrackedResources(data.key(), installable.resources()));
385 } else {
386 trackerService.removeTrackedResources(data.key(), data.intent().resources());
387 intentsToApply.forEach(installable ->
388 trackerService.removeTrackedResources(data.intent().key(),
389 installable.resources()));
390 }
391
392 // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so.
393 builder.newStage();
394
395 List<Collection<FlowRule>> stages = intentsToApply.stream()
396 .map(x -> (FlowRuleIntent) x)
397 .map(FlowRuleIntent::flowRules)
398 .collect(Collectors.toList());
399
400 for (Collection<FlowRule> rules : stages) {
401 if (direction == Direction.ADD) {
402 rules.forEach(builder::add);
403 } else {
404 rules.forEach(builder::remove);
405 }
406 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800407 }
408
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800409 }
410
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700411 private void apply(IntentData toUninstall, IntentData toInstall) {
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800412 // need to consider if FlowRuleIntent is only one as installable intent or not
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800413
414 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700415 applyIntentData(toUninstall, builder, Direction.REMOVE);
416 applyIntentData(toInstall, builder, Direction.ADD);
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800417
418 FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() {
419 @Override
420 public void onSuccess(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700421 if (toInstall != null) {
422 log.debug("Completed installing: {}", toInstall.key());
423 //FIXME state depends on install.... we might want to pass this in.
424 toInstall.setState(INSTALLED);
425 store.write(toInstall);
426 } else if (toUninstall != null) {
427 log.debug("Completed withdrawing: {}", toUninstall.key());
428 //FIXME state depends on install.... we might want to pass this in.
429 toUninstall.setState(WITHDRAWN);
430 store.write(toUninstall);
431 }
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800432 }
433
434 @Override
435 public void onError(FlowRuleOperations ops) {
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700436 if (toInstall != null) {
437 log.warn("Failed installation: {} {} on {}", toInstall.key(), toInstall.intent(), ops);
438 //FIXME
439 toInstall.setState(FAILED);
440 store.write(toInstall);
441 }
442 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
443 // if toUninstall was cause of error, then CORRUPT (another job will lean this up)
Sho SHIMIZUee2aa652015-02-25 18:56:43 -0800444 }
445 });
446
447 flowRuleService.apply(operations);
448 }
449
Brian O'Connor66630c82014-10-02 21:08:19 -0700450}