blob: 3b542bd694242413b81cfe805d977067e1caf2b9 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net.intent.impl;
Brian O'Connor66630c82014-10-02 21:08:19 -070017
Brian O'Connor66630c82014-10-02 21:08:19 -070018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -080021import org.apache.felix.scr.annotations.Modified;
22import org.apache.felix.scr.annotations.Property;
Brian O'Connor66630c82014-10-02 21:08:19 -070023import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
Sho SHIMIZUe0981722016-01-14 16:02:48 -080026import org.onlab.util.Tools;
Sho SHIMIZUd5bf1062016-02-25 10:26:02 -080027import org.onosproject.cfg.ComponentConfigService;
Brian O'Connorabafb502014-12-02 22:26:20 -080028import org.onosproject.core.CoreService;
29import org.onosproject.core.IdGenerator;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080030import org.onosproject.event.AbstractListenerManager;
helenyrwu2a674902016-07-20 09:48:04 -070031import org.onosproject.net.DeviceId;
Andreas Papazois05548962016-11-23 11:36:55 +020032import org.onosproject.net.config.NetworkConfigService;
Andreas Papazoisf00087c2016-11-23 11:36:55 +020033import org.onosproject.net.domain.DomainIntentService;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.net.flow.FlowRuleService;
Thomas Vachuskaf6ec97b2016-02-22 10:59:23 -080035import org.onosproject.net.flowobjective.FlowObjectiveService;
helenyrwu2a674902016-07-20 09:48:04 -070036import org.onosproject.net.group.GroupKey;
37import org.onosproject.net.group.GroupService;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.net.intent.Intent;
39import org.onosproject.net.intent.IntentBatchDelegate;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.net.intent.IntentCompiler;
Brian O'Connorcff03322015-02-03 15:28:59 -080041import org.onosproject.net.intent.IntentData;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.net.intent.IntentEvent;
Brian O'Connorabafb502014-12-02 22:26:20 -080043import org.onosproject.net.intent.IntentExtensionService;
Brian O'Connorabafb502014-12-02 22:26:20 -080044import org.onosproject.net.intent.IntentListener;
Brian O'Connorabafb502014-12-02 22:26:20 -080045import org.onosproject.net.intent.IntentService;
46import org.onosproject.net.intent.IntentState;
47import org.onosproject.net.intent.IntentStore;
Brian O'Connorabafb502014-12-02 22:26:20 -080048import org.onosproject.net.intent.IntentStoreDelegate;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080049import org.onosproject.net.intent.Key;
helenyrwu2a674902016-07-20 09:48:04 -070050import org.onosproject.net.intent.PointToPointIntent;
51import org.onosproject.net.intent.impl.compiler.PointToPointIntentCompiler;
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -080052import org.onosproject.net.intent.impl.phase.FinalIntentProcessPhase;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080053import org.onosproject.net.intent.impl.phase.IntentProcessPhase;
Brian O'Connorc590ebb2016-12-08 18:16:41 -080054import org.onosproject.net.intent.impl.phase.Skipped;
Luca Pretede10c782017-01-05 17:23:08 -080055import org.onosproject.net.resource.ResourceConsumer;
Sho SHIMIZUe18cb122016-02-22 21:04:56 -080056import org.onosproject.net.resource.ResourceService;
Luca Pretede10c782017-01-05 17:23:08 -080057import org.osgi.service.component.ComponentContext;
Brian O'Connor66630c82014-10-02 21:08:19 -070058import org.slf4j.Logger;
59
Brian O'Connorf0c5a052015-04-27 00:34:53 -070060import java.util.Collection;
61import java.util.EnumSet;
62import java.util.List;
63import java.util.Map;
Sho SHIMIZUab541a52016-01-13 23:29:32 -080064import java.util.Objects;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070065import java.util.Optional;
Sho SHIMIZUad8ab272016-01-13 22:08:58 -080066import java.util.concurrent.CompletableFuture;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070067import java.util.concurrent.ExecutorService;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070068import java.util.stream.Collectors;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070069
Brian O'Connorfa81eae2014-10-30 13:20:05 -070070import static com.google.common.base.Preconditions.checkNotNull;
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -080071import static com.google.common.base.Strings.isNullOrEmpty;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080072import static java.util.concurrent.Executors.newFixedThreadPool;
Brian O'Connordb15b042015-02-04 14:59:28 -080073import static java.util.concurrent.Executors.newSingleThreadExecutor;
Brian O'Connorbdc7f002015-02-18 20:49:41 -080074import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuskaf6ec97b2016-02-22 10:59:23 -080075import static org.onosproject.net.intent.IntentState.*;
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070076import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080077import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
Changhoon Yoon541ef712015-05-23 17:18:34 +090078import static org.onosproject.security.AppGuard.checkPermission;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080079import static org.onosproject.security.AppPermission.Type.INTENT_READ;
80import static org.onosproject.security.AppPermission.Type.INTENT_WRITE;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070081import static org.slf4j.LoggerFactory.getLogger;
Changhoon Yoonb856b812015-08-10 03:47:19 +090082
Brian O'Connor66630c82014-10-02 21:08:19 -070083/**
Brian O'Connorce2d8b52015-07-29 16:24:13 -070084 * An implementation of intent service.
Brian O'Connor66630c82014-10-02 21:08:19 -070085 */
86@Component(immediate = true)
87@Service
88public class IntentManager
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070089 extends AbstractListenerManager<IntentEvent, IntentListener>
Brian O'Connor66630c82014-10-02 21:08:19 -070090 implements IntentService, IntentExtensionService {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070091
Sho SHIMIZU8b5051d2014-11-05 11:24:13 -080092 private static final Logger log = getLogger(IntentManager.class);
Brian O'Connor66630c82014-10-02 21:08:19 -070093
Sho SHIMIZU17c09da2016-03-31 12:54:17 -070094 private static final String INTENT_NULL = "Intent cannot be null";
95 private static final String INTENT_ID_NULL = "Intent key cannot be null";
Brian O'Connor66630c82014-10-02 21:08:19 -070096
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080097 private static final EnumSet<IntentState> RECOMPILE
98 = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070099 private static final EnumSet<IntentState> WITHDRAW
100 = EnumSet.of(WITHDRAW_REQ, WITHDRAWING, WITHDRAWN);
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800101
Thomas Vachuskabdbdd242016-03-01 01:55:55 -0800102 private static final boolean DEFAULT_SKIP_RELEASE_RESOURCES_ON_WITHDRAWAL = false;
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800103 @Property(name = "skipReleaseResourcesOnWithdrawal",
104 boolValue = DEFAULT_SKIP_RELEASE_RESOURCES_ON_WITHDRAWAL,
105 label = "Indicates whether skipping resource releases on withdrawal is enabled or not")
106 private boolean skipReleaseResourcesOnWithdrawal = DEFAULT_SKIP_RELEASE_RESOURCES_ON_WITHDRAWAL;
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800107
Thomas Vachuskabdbdd242016-03-01 01:55:55 -0800108 private static final int DEFAULT_NUM_THREADS = 12;
109 @Property(name = "numThreads",
110 intValue = DEFAULT_NUM_THREADS,
111 label = "Number of worker threads")
112 private int numThreads = DEFAULT_NUM_THREADS;
113
Brian O'Connor520c0522014-11-23 23:50:47 -0800114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected CoreService coreService;
Brian O'Connor66630c82014-10-02 21:08:19 -0700116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected IntentStore store;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
tom85258ee2014-10-07 00:10:02 -0700121 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -0700122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZU214ac322015-02-23 19:30:15 -0800124 protected FlowRuleService flowRuleService;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700125
Naoki Shiotabbc7ead2016-01-20 14:10:38 -0800126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Thomas Vachuskaf6ec97b2016-02-22 10:59:23 -0800127 protected FlowObjectiveService flowObjectiveService;
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andreas Papazoisf00087c2016-11-23 11:36:55 +0200130 protected DomainIntentService domainIntentService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Naoki Shiotabbc7ead2016-01-20 14:10:38 -0800133 protected ResourceService resourceService;
134
Sho SHIMIZUd5bf1062016-02-25 10:26:02 -0800135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
136 protected ComponentConfigService configService;
137
helenyrwu2a674902016-07-20 09:48:04 -0700138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
139 protected GroupService groupService;
140
Andreas Papazois05548962016-11-23 11:36:55 +0200141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
142 private NetworkConfigService networkConfigService;
143
144
Brian O'Connordb15b042015-02-04 14:59:28 -0800145 private ExecutorService batchExecutor;
146 private ExecutorService workerExecutor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800147
Thomas Vachuskaf6ec97b2016-02-22 10:59:23 -0800148 private final IntentInstaller intentInstaller = new IntentInstaller();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800149 private final CompilerRegistry compilerRegistry = new CompilerRegistry();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800150 private final InternalIntentProcessor processor = new InternalIntentProcessor();
Brian O'Connor520c0522014-11-23 23:50:47 -0800151 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800152 private final IntentStoreDelegate testOnlyDelegate = new TestOnlyIntentStoreDelegate();
Brian O'Connor520c0522014-11-23 23:50:47 -0800153 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
154 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
155 private IdGenerator idGenerator;
156
Brian O'Connorb499b352015-02-03 16:46:15 -0800157 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800158
Brian O'Connor66630c82014-10-02 21:08:19 -0700159 @Activate
160 public void activate() {
Sho SHIMIZUd5bf1062016-02-25 10:26:02 -0800161 configService.registerProperties(getClass());
162
Andreas Papazois05548962016-11-23 11:36:55 +0200163 intentInstaller.init(store, trackerService, flowRuleService, flowObjectiveService,
Andreas Papazoisf00087c2016-11-23 11:36:55 +0200164 networkConfigService, domainIntentService);
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800165 if (skipReleaseResourcesOnWithdrawal) {
166 store.setDelegate(testOnlyDelegate);
167 } else {
168 store.setDelegate(delegate);
169 }
tom95329eb2014-10-06 08:40:06 -0700170 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700171 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700172 batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch", log));
173 workerExecutor = newFixedThreadPool(numThreads, groupedThreads("onos/intent", "worker-%d", log));
Brian O'Connor520c0522014-11-23 23:50:47 -0800174 idGenerator = coreService.getIdGenerator("intent-ids");
Thomas Vachuska23235962017-02-03 11:44:15 -0800175 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor520c0522014-11-23 23:50:47 -0800176 Intent.bindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700177 log.info("Started");
178 }
179
180 @Deactivate
181 public void deactivate() {
Andreas Papazoisf00087c2016-11-23 11:36:55 +0200182 intentInstaller.init(null, null, null, null, null, null);
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800183 if (skipReleaseResourcesOnWithdrawal) {
184 store.unsetDelegate(testOnlyDelegate);
185 } else {
186 store.unsetDelegate(delegate);
187 }
Sho SHIMIZUd5bf1062016-02-25 10:26:02 -0800188 configService.unregisterProperties(getClass(), false);
tom95329eb2014-10-06 08:40:06 -0700189 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700190 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connordb15b042015-02-04 14:59:28 -0800191 batchExecutor.shutdown();
Brian O'Connor3c58e962015-04-28 23:21:51 -0700192 workerExecutor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800193 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700194 log.info("Stopped");
195 }
196
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800197 @Modified
198 public void modified(ComponentContext context) {
199 if (context == null) {
200 skipReleaseResourcesOnWithdrawal = DEFAULT_SKIP_RELEASE_RESOURCES_ON_WITHDRAWAL;
201 logConfig("Default config");
202 return;
203 }
204
205 String s = Tools.get(context.getProperties(), "skipReleaseResourcesOnWithdrawal");
206 boolean newTestEnabled = isNullOrEmpty(s) ? skipReleaseResourcesOnWithdrawal : Boolean.parseBoolean(s.trim());
207 if (skipReleaseResourcesOnWithdrawal && !newTestEnabled) {
208 store.unsetDelegate(testOnlyDelegate);
209 store.setDelegate(delegate);
Thomas Vachuskabdbdd242016-03-01 01:55:55 -0800210 skipReleaseResourcesOnWithdrawal = false;
211 logConfig("Reconfigured skip release resources on withdrawal");
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800212 } else if (!skipReleaseResourcesOnWithdrawal && newTestEnabled) {
213 store.unsetDelegate(delegate);
214 store.setDelegate(testOnlyDelegate);
Thomas Vachuskabdbdd242016-03-01 01:55:55 -0800215 skipReleaseResourcesOnWithdrawal = true;
216 logConfig("Reconfigured skip release resources on withdrawal");
217 }
218
219 s = Tools.get(context.getProperties(), "numThreads");
220 int newNumThreads = isNullOrEmpty(s) ? numThreads : Integer.parseInt(s);
221 if (newNumThreads != numThreads) {
222 numThreads = newNumThreads;
223 ExecutorService oldWorkerExecutor = workerExecutor;
HIGUCHI Yuta060da9a2016-03-11 19:16:35 -0800224 workerExecutor = newFixedThreadPool(numThreads, groupedThreads("onos/intent", "worker-%d", log));
Thomas Vachuskabdbdd242016-03-01 01:55:55 -0800225 if (oldWorkerExecutor != null) {
226 oldWorkerExecutor.shutdown();
227 }
228 logConfig("Reconfigured number of worker threads");
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800229 }
230 }
231
232 private void logConfig(String prefix) {
233 log.info("{} with skipReleaseResourcesOnWithdrawal = {}", prefix, skipReleaseResourcesOnWithdrawal);
234 }
235
Brian O'Connor66630c82014-10-02 21:08:19 -0700236 @Override
237 public void submit(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900238 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700239 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800240 IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800241 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700242 }
243
244 @Override
245 public void withdraw(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900246 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700247 checkNotNull(intent, INTENT_NULL);
Brian O'Connorcff03322015-02-03 15:28:59 -0800248 IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null);
Brian O'Connorcff03322015-02-03 15:28:59 -0800249 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700250 }
251
Brian O'Connor66630c82014-10-02 21:08:19 -0700252 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700253 public void purge(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900254 checkPermission(INTENT_WRITE);
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700255 checkNotNull(intent, INTENT_NULL);
256 IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null);
257 store.addPending(data);
helenyrwu2a674902016-07-20 09:48:04 -0700258
259 // remove associated group if there is one
260 if (intent instanceof PointToPointIntent) {
261 PointToPointIntent pointIntent = (PointToPointIntent) intent;
262 DeviceId deviceId = pointIntent.ingressPoint().deviceId();
263 GroupKey groupKey = PointToPointIntentCompiler.makeGroupKey(intent.id());
264 groupService.removeGroup(deviceId, groupKey,
265 intent.appId());
266 }
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700267 }
268
269 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800270 public Intent getIntent(Key key) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900271 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800272 return store.getIntent(key);
273 }
274
275 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700276 public Iterable<Intent> getIntents() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900277 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700278 return store.getIntents();
279 }
280
281 @Override
Brian O'Connor38224302016-08-02 22:03:01 -0700282 public void addPending(IntentData intentData) {
283 checkPermission(INTENT_WRITE);
284 checkNotNull(intentData, INTENT_NULL);
285 //TODO we might consider further checking / assertions
286 store.addPending(intentData);
287 }
288
289 @Override
Thomas Vachuskac46af202015-06-03 16:43:27 -0700290 public Iterable<IntentData> getIntentData() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900291 checkPermission(INTENT_READ);
Thomas Vachuskac46af202015-06-03 16:43:27 -0700292 return store.getIntentData(false, 0);
293 }
294
295 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700296 public long getIntentCount() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900297 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700298 return store.getIntentCount();
299 }
300
301 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800302 public IntentState getIntentState(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900303 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800304 checkNotNull(intentKey, INTENT_ID_NULL);
305 return store.getIntentState(intentKey);
Brian O'Connor66630c82014-10-02 21:08:19 -0700306 }
307
308 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800309 public List<Intent> getInstallableIntents(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900310 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800311 checkNotNull(intentKey, INTENT_ID_NULL);
312 return store.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700313 }
314
315 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800316 public boolean isLocal(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900317 checkPermission(INTENT_READ);
Brian O'Connorbe28a872015-02-19 21:44:37 -0800318 return store.isMaster(intentKey);
319 }
320
321 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700322 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900323 checkPermission(INTENT_WRITE);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800324 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700325 }
326
327 @Override
328 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900329 checkPermission(INTENT_WRITE);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800330 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700331 }
332
333 @Override
334 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Heedo Kang4a47a302016-02-29 17:40:23 +0900335 checkPermission(INTENT_READ);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800336 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700337 }
338
339 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800340 public Iterable<Intent> getPending() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900341 checkPermission(INTENT_READ);
Jonathan Hart34f1e382015-02-24 16:52:23 -0800342 return store.getPending();
343 }
344
Brian O'Connor66630c82014-10-02 21:08:19 -0700345 // Store delegate to re-post events emitted from the store.
346 private class InternalStoreDelegate implements IntentStoreDelegate {
347 @Override
348 public void notify(IntentEvent event) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700349 post(event);
Naoki Shiotabbc7ead2016-01-20 14:10:38 -0800350 switch (event.type()) {
351 case WITHDRAWN:
Luca Pretede10c782017-01-05 17:23:08 -0800352 if (!skipReleaseResourcesOnWithdrawal) {
353 releaseResources(event.subject());
Naoki Shiotabbc7ead2016-01-20 14:10:38 -0800354 }
355 break;
356 default:
357 break;
358 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700359 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800360
361 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800362 public void process(IntentData data) {
363 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800364 }
Thomas Vachuskac46af202015-06-03 16:43:27 -0700365
366 @Override
367 public void onUpdate(IntentData intentData) {
368 trackerService.trackIntent(intentData);
369 }
Luca Pretede10c782017-01-05 17:23:08 -0800370
371 private void releaseResources(Intent intent) {
372 // If a resource group is set on the intent, the resource consumer is
373 // set equal to it. Otherwise it's set to the intent key
374 ResourceConsumer resourceConsumer =
375 intent.resourceGroup() != null ? intent.resourceGroup() : intent.key();
376
377 // By default the resource doesn't get released
378 boolean removeResource = false;
379
380 if (intent.resourceGroup() == null) {
381 // If the intent doesn't have a resource group, it means the
382 // resource was registered using the intent key, so it can be
383 // released
384 removeResource = true;
385 } else {
386 // When a resource group is set, we make sure there are no other
387 // intents using the same resource group, before deleting the
388 // related resources.
389 Long remainingIntents =
390 Tools.stream(store.getIntents())
Yi Tseng2ef80142017-02-17 15:56:32 -0800391 .filter(i -> {
392 return i.resourceGroup() != null
393 && i.resourceGroup().equals(intent.resourceGroup());
394 })
Luca Pretede10c782017-01-05 17:23:08 -0800395 .count();
396 if (remainingIntents == 0) {
397 removeResource = true;
398 }
399 }
400
401 if (removeResource) {
402 // Release resources allocated to withdrawn intent
403 if (!resourceService.release(resourceConsumer)) {
404 log.error("Failed to release resources allocated to {}", resourceConsumer);
405 }
406 }
407 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700408 }
409
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800410 // Store delegate enabled only when performing intent throughput tests
411 private class TestOnlyIntentStoreDelegate implements IntentStoreDelegate {
412 @Override
413 public void process(IntentData data) {
414 accumulator.add(data);
415 }
416
417 @Override
418 public void onUpdate(IntentData data) {
419 trackerService.trackIntent(data);
420 }
421
422 @Override
423 public void notify(IntentEvent event) {
424 post(event);
425 }
426 }
427
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800428 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800429 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800430 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800431 for (Key key : intentKeys) {
432 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800433 if (intent == null) {
434 continue;
435 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800436 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800437 }
438
Jonathan Hart0cca3e82015-09-23 17:54:11 -0700439 if (compileAllFailed) {
440 // If required, compile all currently failed intents.
441 for (Intent intent : getIntents()) {
442 IntentState state = getIntentState(intent.key());
443 if (RECOMPILE.contains(state) || intentAllowsPartialFailure(intent)) {
444 if (WITHDRAW.contains(state)) {
445 withdraw(intent);
446 } else {
447 submit(intent);
448 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800449 }
450 }
451 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800452 }
453
tom95329eb2014-10-06 08:40:06 -0700454 // Topology change delegate
455 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
456 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800457 public void triggerCompile(Iterable<Key> intentKeys,
tom85258ee2014-10-07 00:10:02 -0700458 boolean compileAllFailed) {
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800459 buildAndSubmitBatches(intentKeys, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700460 }
tom95329eb2014-10-06 08:40:06 -0700461 }
tom85258ee2014-10-07 00:10:02 -0700462
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700463 private class InternalBatchDelegate implements IntentBatchDelegate {
464 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800465 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800466 log.debug("Execute {} operation(s).", operations.size());
467 log.trace("Execute operations: {}", operations);
Sho SHIMIZU94b03b12015-04-10 14:53:13 -0700468
469 // batchExecutor is single-threaded, so only one batch is in flight at a time
Sho SHIMIZU489aa9b2016-01-14 17:19:32 -0800470 CompletableFuture.runAsync(() -> {
Sho SHIMIZU8f2b7772016-01-14 18:17:44 -0800471 // process intent until the phase reaches one of the final phases
472 List<CompletableFuture<IntentData>> futures = operations.stream()
473 .map(x -> CompletableFuture.completedFuture(x)
474 .thenApply(IntentManager.this::createInitialPhase)
Sho SHIMIZU4a141852016-01-14 18:55:40 -0800475 .thenApplyAsync(IntentProcessPhase::process, workerExecutor)
Sho SHIMIZU8f2b7772016-01-14 18:17:44 -0800476 .thenApply(FinalIntentProcessPhase::data)
477 .exceptionally(e -> {
Pier Luigi13b287f2017-01-10 15:07:52 -0800478 // When the future fails, we update the Intent to simulate the failure of
479 // the installation/withdrawal phase and we save in the current map. In
480 // the next round the CleanUp Thread will pick this Intent again.
481 log.warn("Future failed", e);
482 log.warn("Intent {} - state {} - request {}",
483 x.key(), x.state(), x.request());
484 switch (x.state()) {
485 case INSTALL_REQ:
486 case INSTALLING:
487 case WITHDRAW_REQ:
488 case WITHDRAWING:
489 x.setState(FAILED);
490 IntentData current = store.getIntentData(x.key());
491 return new IntentData(x, current.installables());
492 default:
493 return null;
494 }
Brian O'Connorc590ebb2016-12-08 18:16:41 -0800495 }))
496 .collect(Collectors.toList());
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800497
Sho SHIMIZU8f2b7772016-01-14 18:17:44 -0800498 // write multiple data to store in order
499 store.batchWrite(Tools.allOf(futures).join().stream()
Thomas Vachuskaf6ec97b2016-02-22 10:59:23 -0800500 .filter(Objects::nonNull)
501 .collect(Collectors.toList()));
Sho SHIMIZU8f2b7772016-01-14 18:17:44 -0800502 }, batchExecutor).exceptionally(e -> {
503 log.error("Error submitting batches:", e);
504 // FIXME incomplete Intents should be cleaned up
505 // (transition to FAILED, etc.)
506
507 // the batch has failed
508 // TODO: maybe we should do more?
509 log.error("Walk the plank, matey...");
Sho SHIMIZU8f2b7772016-01-14 18:17:44 -0800510 return null;
511 }).thenRun(accumulator::ready);
512
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700513 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700514 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800515
Sho SHIMIZUc88b85e2016-01-14 18:45:14 -0800516 private IntentProcessPhase createInitialPhase(IntentData data) {
Brian O'Connorc590ebb2016-12-08 18:16:41 -0800517 IntentData pending = store.getPendingData(data.key());
518 if (pending == null || pending.version().isNewerThan(data.version())) {
519 /*
520 If the pending map is null, then this intent was compiled by a
521 previous batch iteration, so we can skip it.
522 If the pending map has a newer request, it will get compiled as
523 part of the next batch, so we can skip it.
524 */
525 return Skipped.getPhase();
526 }
Sho SHIMIZUc88b85e2016-01-14 18:45:14 -0800527 IntentData current = store.getIntentData(data.key());
528 return newInitialPhase(processor, data, current);
529 }
530
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800531 private class InternalIntentProcessor implements IntentProcessor {
532 @Override
533 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
534 return compilerRegistry.compile(intent, previousInstallables);
535 }
536
537 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700538 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Thomas Vachuskaf6ec97b2016-02-22 10:59:23 -0800539 intentInstaller.apply(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800540 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700541 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800542
Brian O'Connor66630c82014-10-02 21:08:19 -0700543}