blob: 2b83fa8a0296382d6bfa3ebbfd35ef26f56f546e [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
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
Sho SHIMIZUe0981722016-01-14 16:02:48 -080018import org.onlab.util.Tools;
Sho SHIMIZUd5bf1062016-02-25 10:26:02 -080019import org.onosproject.cfg.ComponentConfigService;
Brian O'Connorabafb502014-12-02 22:26:20 -080020import org.onosproject.core.CoreService;
21import org.onosproject.core.IdGenerator;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080022import org.onosproject.event.AbstractListenerManager;
helenyrwu2a674902016-07-20 09:48:04 -070023import org.onosproject.net.DeviceId;
Andreas Papazois05548962016-11-23 11:36:55 +020024import org.onosproject.net.config.NetworkConfigService;
Andreas Papazoisf00087c2016-11-23 11:36:55 +020025import org.onosproject.net.domain.DomainIntentService;
Brian O'Connorabafb502014-12-02 22:26:20 -080026import org.onosproject.net.flow.FlowRuleService;
Thomas Vachuskaf6ec97b2016-02-22 10:59:23 -080027import org.onosproject.net.flowobjective.FlowObjectiveService;
helenyrwu2a674902016-07-20 09:48:04 -070028import org.onosproject.net.group.GroupKey;
29import org.onosproject.net.group.GroupService;
Brian O'Connorabafb502014-12-02 22:26:20 -080030import org.onosproject.net.intent.Intent;
31import org.onosproject.net.intent.IntentBatchDelegate;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.net.intent.IntentCompiler;
Brian O'Connorcff03322015-02-03 15:28:59 -080033import org.onosproject.net.intent.IntentData;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.net.intent.IntentEvent;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.intent.IntentExtensionService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070036import org.onosproject.net.intent.IntentInstallCoordinator;
Yi Tsengc927a062017-05-02 15:02:37 -070037import org.onosproject.net.intent.IntentInstaller;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.net.intent.IntentListener;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070039import org.onosproject.net.intent.IntentOperationContext;
Brian O'Connorabafb502014-12-02 22:26:20 -080040import org.onosproject.net.intent.IntentService;
41import org.onosproject.net.intent.IntentState;
42import org.onosproject.net.intent.IntentStore;
Brian O'Connorabafb502014-12-02 22:26:20 -080043import org.onosproject.net.intent.IntentStoreDelegate;
Ray Milkeyf9af43c2015-02-09 16:45:48 -080044import org.onosproject.net.intent.Key;
Yi Tseng24d9be72017-05-12 11:28:13 -070045import org.onosproject.net.intent.ObjectiveTrackerService;
helenyrwu2a674902016-07-20 09:48:04 -070046import org.onosproject.net.intent.PointToPointIntent;
Yi Tseng24d9be72017-05-12 11:28:13 -070047import org.onosproject.net.intent.TopologyChangeDelegate;
helenyrwu2a674902016-07-20 09:48:04 -070048import org.onosproject.net.intent.impl.compiler.PointToPointIntentCompiler;
Sho SHIMIZU36a8a6e2015-02-13 15:38:45 -080049import org.onosproject.net.intent.impl.phase.FinalIntentProcessPhase;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080050import org.onosproject.net.intent.impl.phase.IntentProcessPhase;
Brian O'Connorc590ebb2016-12-08 18:16:41 -080051import org.onosproject.net.intent.impl.phase.Skipped;
Luca Pretede10c782017-01-05 17:23:08 -080052import org.onosproject.net.resource.ResourceConsumer;
Sho SHIMIZUe18cb122016-02-22 21:04:56 -080053import org.onosproject.net.resource.ResourceService;
Luca Pretede10c782017-01-05 17:23:08 -080054import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070055import org.osgi.service.component.annotations.Activate;
56import org.osgi.service.component.annotations.Component;
57import org.osgi.service.component.annotations.Deactivate;
58import org.osgi.service.component.annotations.Modified;
59import org.osgi.service.component.annotations.Reference;
60import org.osgi.service.component.annotations.ReferenceCardinality;
Brian O'Connor66630c82014-10-02 21:08:19 -070061import org.slf4j.Logger;
62
Brian O'Connorf0c5a052015-04-27 00:34:53 -070063import java.util.Collection;
64import java.util.EnumSet;
65import java.util.List;
66import java.util.Map;
Sho SHIMIZUab541a52016-01-13 23:29:32 -080067import java.util.Objects;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070068import java.util.Optional;
Sho SHIMIZUad8ab272016-01-13 22:08:58 -080069import java.util.concurrent.CompletableFuture;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070070import java.util.concurrent.ExecutorService;
Brian O'Connorf0c5a052015-04-27 00:34:53 -070071import java.util.stream.Collectors;
Brian O'Connorfa81eae2014-10-30 13:20:05 -070072
Brian O'Connorfa81eae2014-10-30 13:20:05 -070073import static com.google.common.base.Preconditions.checkNotNull;
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -080074import static com.google.common.base.Strings.isNullOrEmpty;
Yuta HIGUCHIc2bf3d82014-11-28 18:50:41 -080075import static java.util.concurrent.Executors.newFixedThreadPool;
Brian O'Connordb15b042015-02-04 14:59:28 -080076import static java.util.concurrent.Executors.newSingleThreadExecutor;
Brian O'Connorbdc7f002015-02-18 20:49:41 -080077import static org.onlab.util.Tools.groupedThreads;
Ray Milkeyd04e2272018-10-16 18:20:18 -070078import static org.onosproject.net.OsgiPropertyConstants.IM_NUM_THREADS;
79import static org.onosproject.net.OsgiPropertyConstants.IM_NUM_THREADS_DEFAULT;
80import static org.onosproject.net.OsgiPropertyConstants.IM_SKIP_RELEASE_RESOURCES_ON_WITHDRAWAL;
81import static org.onosproject.net.OsgiPropertyConstants.IM_SKIP_RELEASE_RESOURCES_ON_WITHDRAWAL_DEFAULT;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070082import static org.onosproject.net.intent.IntentState.FAILED;
83import static org.onosproject.net.intent.IntentState.INSTALL_REQ;
84import static org.onosproject.net.intent.IntentState.WITHDRAWING;
85import static org.onosproject.net.intent.IntentState.WITHDRAWN;
86import static org.onosproject.net.intent.IntentState.WITHDRAW_REQ;
Jonathan Hart96c5a4a2015-07-31 14:23:33 -070087import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
Sho SHIMIZUce49b602015-02-23 19:15:49 -080088import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase;
Changhoon Yoon541ef712015-05-23 17:18:34 +090089import static org.onosproject.security.AppGuard.checkPermission;
Sho SHIMIZU98c0a392016-01-14 18:40:53 -080090import static org.onosproject.security.AppPermission.Type.INTENT_READ;
91import static org.onosproject.security.AppPermission.Type.INTENT_WRITE;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070092import static org.slf4j.LoggerFactory.getLogger;
Changhoon Yoonb856b812015-08-10 03:47:19 +090093
Brian O'Connor66630c82014-10-02 21:08:19 -070094/**
Brian O'Connorce2d8b52015-07-29 16:24:13 -070095 * An implementation of intent service.
Brian O'Connor66630c82014-10-02 21:08:19 -070096 */
Ray Milkeyd04e2272018-10-16 18:20:18 -070097@Component(
98 immediate = true,
99 service = {
100 IntentService.class,
101 IntentExtensionService.class,
102 IntentInstallCoordinator.class
103 },
104 property = {
Ray Milkey2d7bca12018-10-17 14:51:52 -0700105 IM_SKIP_RELEASE_RESOURCES_ON_WITHDRAWAL + ":Boolean=" + IM_SKIP_RELEASE_RESOURCES_ON_WITHDRAWAL_DEFAULT,
106 IM_NUM_THREADS + ":Integer=" + IM_NUM_THREADS_DEFAULT
Ray Milkeyd04e2272018-10-16 18:20:18 -0700107 }
108)
Brian O'Connor66630c82014-10-02 21:08:19 -0700109public class IntentManager
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700110 extends AbstractListenerManager<IntentEvent, IntentListener>
Yi Tsengc927a062017-05-02 15:02:37 -0700111 implements IntentService, IntentExtensionService, IntentInstallCoordinator {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700112
Sho SHIMIZU8b5051d2014-11-05 11:24:13 -0800113 private static final Logger log = getLogger(IntentManager.class);
Brian O'Connor66630c82014-10-02 21:08:19 -0700114
Sho SHIMIZU17c09da2016-03-31 12:54:17 -0700115 private static final String INTENT_NULL = "Intent cannot be null";
116 private static final String INTENT_ID_NULL = "Intent key cannot be null";
Brian O'Connor66630c82014-10-02 21:08:19 -0700117
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800118 private static final EnumSet<IntentState> RECOMPILE
119 = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ);
Jonathan Hart96c5a4a2015-07-31 14:23:33 -0700120 private static final EnumSet<IntentState> WITHDRAW
121 = EnumSet.of(WITHDRAW_REQ, WITHDRAWING, WITHDRAWN);
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800122
Thomas Vachuskaf566fa22018-10-30 14:03:36 -0700123 /** Indicates whether skipping resource releases on withdrawal is enabled or not. */
Ray Milkeyd04e2272018-10-16 18:20:18 -0700124 private boolean skipReleaseResourcesOnWithdrawal = IM_SKIP_RELEASE_RESOURCES_ON_WITHDRAWAL_DEFAULT;
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800125
Thomas Vachuskaf566fa22018-10-30 14:03:36 -0700126 /** Number of worker threads. */
Ray Milkeyd04e2272018-10-16 18:20:18 -0700127 private int numThreads = IM_NUM_THREADS_DEFAULT;
Thomas Vachuskabdbdd242016-03-01 01:55:55 -0800128
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Brian O'Connor520c0522014-11-23 23:50:47 -0800130 protected CoreService coreService;
Brian O'Connor66630c82014-10-02 21:08:19 -0700131
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Brian O'Connor66630c82014-10-02 21:08:19 -0700133 protected IntentStore store;
134
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700135 @Reference(cardinality = ReferenceCardinality.MANDATORY)
tom85258ee2014-10-07 00:10:02 -0700136 protected ObjectiveTrackerService trackerService;
tom95329eb2014-10-06 08:40:06 -0700137
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700138 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Sho SHIMIZU214ac322015-02-23 19:30:15 -0800139 protected FlowRuleService flowRuleService;
Brian O'Connorf2dbde52014-10-10 16:20:24 -0700140
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700141 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskaf6ec97b2016-02-22 10:59:23 -0800142 protected FlowObjectiveService flowObjectiveService;
143
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700144 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andreas Papazoisf00087c2016-11-23 11:36:55 +0200145 protected DomainIntentService domainIntentService;
146
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700147 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Naoki Shiotabbc7ead2016-01-20 14:10:38 -0800148 protected ResourceService resourceService;
149
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700150 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Sho SHIMIZUd5bf1062016-02-25 10:26:02 -0800151 protected ComponentConfigService configService;
152
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700153 @Reference(cardinality = ReferenceCardinality.MANDATORY)
helenyrwu2a674902016-07-20 09:48:04 -0700154 protected GroupService groupService;
155
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700156 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andreas Papazois05548962016-11-23 11:36:55 +0200157 private NetworkConfigService networkConfigService;
158
Brian O'Connordb15b042015-02-04 14:59:28 -0800159 private ExecutorService batchExecutor;
160 private ExecutorService workerExecutor;
Brian O'Connor520c0522014-11-23 23:50:47 -0800161
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800162 private final CompilerRegistry compilerRegistry = new CompilerRegistry();
Yi Tsengc927a062017-05-02 15:02:37 -0700163 private final InstallerRegistry installerRegistry = new InstallerRegistry();
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800164 private final InternalIntentProcessor processor = new InternalIntentProcessor();
Brian O'Connor520c0522014-11-23 23:50:47 -0800165 private final IntentStoreDelegate delegate = new InternalStoreDelegate();
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800166 private final IntentStoreDelegate testOnlyDelegate = new TestOnlyIntentStoreDelegate();
Brian O'Connor520c0522014-11-23 23:50:47 -0800167 private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate();
168 private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate();
Yi Tsengc927a062017-05-02 15:02:37 -0700169 private InstallCoordinator installCoordinator;
Brian O'Connor520c0522014-11-23 23:50:47 -0800170 private IdGenerator idGenerator;
171
Brian O'Connorb499b352015-02-03 16:46:15 -0800172 private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate);
Brian O'Connorcff03322015-02-03 15:28:59 -0800173
Brian O'Connor66630c82014-10-02 21:08:19 -0700174 @Activate
175 public void activate() {
Sho SHIMIZUd5bf1062016-02-25 10:26:02 -0800176 configService.registerProperties(getClass());
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800177 if (skipReleaseResourcesOnWithdrawal) {
178 store.setDelegate(testOnlyDelegate);
179 } else {
180 store.setDelegate(delegate);
181 }
tom95329eb2014-10-06 08:40:06 -0700182 trackerService.setDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700183 eventDispatcher.addSink(IntentEvent.class, listenerRegistry);
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700184 batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch", log));
185 workerExecutor = newFixedThreadPool(numThreads, groupedThreads("onos/intent", "worker-%d", log));
Brian O'Connor520c0522014-11-23 23:50:47 -0800186 idGenerator = coreService.getIdGenerator("intent-ids");
Thomas Vachuska23235962017-02-03 11:44:15 -0800187 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor520c0522014-11-23 23:50:47 -0800188 Intent.bindIdGenerator(idGenerator);
Yi Tsengc927a062017-05-02 15:02:37 -0700189 installCoordinator = new InstallCoordinator(installerRegistry, store);
Brian O'Connor66630c82014-10-02 21:08:19 -0700190 log.info("Started");
191 }
192
193 @Deactivate
194 public void deactivate() {
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800195 if (skipReleaseResourcesOnWithdrawal) {
196 store.unsetDelegate(testOnlyDelegate);
197 } else {
198 store.unsetDelegate(delegate);
199 }
Sho SHIMIZUd5bf1062016-02-25 10:26:02 -0800200 configService.unregisterProperties(getClass(), false);
tom95329eb2014-10-06 08:40:06 -0700201 trackerService.unsetDelegate(topoDelegate);
Brian O'Connor66630c82014-10-02 21:08:19 -0700202 eventDispatcher.removeSink(IntentEvent.class);
Brian O'Connordb15b042015-02-04 14:59:28 -0800203 batchExecutor.shutdown();
Brian O'Connor3c58e962015-04-28 23:21:51 -0700204 workerExecutor.shutdown();
Brian O'Connor520c0522014-11-23 23:50:47 -0800205 Intent.unbindIdGenerator(idGenerator);
Brian O'Connor66630c82014-10-02 21:08:19 -0700206 log.info("Stopped");
207 }
208
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800209 @Modified
210 public void modified(ComponentContext context) {
211 if (context == null) {
Ray Milkeyd04e2272018-10-16 18:20:18 -0700212 skipReleaseResourcesOnWithdrawal = IM_SKIP_RELEASE_RESOURCES_ON_WITHDRAWAL_DEFAULT;
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800213 logConfig("Default config");
214 return;
215 }
216
Thomas Vachuskaf566fa22018-10-30 14:03:36 -0700217 String s = Tools.get(context.getProperties(), IM_SKIP_RELEASE_RESOURCES_ON_WITHDRAWAL);
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800218 boolean newTestEnabled = isNullOrEmpty(s) ? skipReleaseResourcesOnWithdrawal : Boolean.parseBoolean(s.trim());
219 if (skipReleaseResourcesOnWithdrawal && !newTestEnabled) {
220 store.unsetDelegate(testOnlyDelegate);
221 store.setDelegate(delegate);
Thomas Vachuskabdbdd242016-03-01 01:55:55 -0800222 skipReleaseResourcesOnWithdrawal = false;
223 logConfig("Reconfigured skip release resources on withdrawal");
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800224 } else if (!skipReleaseResourcesOnWithdrawal && newTestEnabled) {
225 store.unsetDelegate(delegate);
226 store.setDelegate(testOnlyDelegate);
Thomas Vachuskabdbdd242016-03-01 01:55:55 -0800227 skipReleaseResourcesOnWithdrawal = true;
228 logConfig("Reconfigured skip release resources on withdrawal");
229 }
230
Thomas Vachuskaf566fa22018-10-30 14:03:36 -0700231 s = Tools.get(context.getProperties(), IM_NUM_THREADS);
Thomas Vachuskabdbdd242016-03-01 01:55:55 -0800232 int newNumThreads = isNullOrEmpty(s) ? numThreads : Integer.parseInt(s);
233 if (newNumThreads != numThreads) {
234 numThreads = newNumThreads;
235 ExecutorService oldWorkerExecutor = workerExecutor;
HIGUCHI Yuta060da9a2016-03-11 19:16:35 -0800236 workerExecutor = newFixedThreadPool(numThreads, groupedThreads("onos/intent", "worker-%d", log));
Thomas Vachuskabdbdd242016-03-01 01:55:55 -0800237 if (oldWorkerExecutor != null) {
238 oldWorkerExecutor.shutdown();
239 }
240 logConfig("Reconfigured number of worker threads");
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800241 }
242 }
243
244 private void logConfig(String prefix) {
245 log.info("{} with skipReleaseResourcesOnWithdrawal = {}", prefix, skipReleaseResourcesOnWithdrawal);
246 }
247
Brian O'Connor66630c82014-10-02 21:08:19 -0700248 @Override
249 public void submit(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900250 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700251 checkNotNull(intent, INTENT_NULL);
Yuta HIGUCHI4f8a3772017-05-16 20:23:49 -0700252 IntentData data = IntentData.submit(intent);
Brian O'Connorcff03322015-02-03 15:28:59 -0800253 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700254 }
255
256 @Override
257 public void withdraw(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900258 checkPermission(INTENT_WRITE);
Brian O'Connor66630c82014-10-02 21:08:19 -0700259 checkNotNull(intent, INTENT_NULL);
Yuta HIGUCHI4f8a3772017-05-16 20:23:49 -0700260 IntentData data = IntentData.withdraw(intent);
Brian O'Connorcff03322015-02-03 15:28:59 -0800261 store.addPending(data);
Brian O'Connor66630c82014-10-02 21:08:19 -0700262 }
263
Brian O'Connor66630c82014-10-02 21:08:19 -0700264 @Override
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700265 public void purge(Intent intent) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900266 checkPermission(INTENT_WRITE);
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700267 checkNotNull(intent, INTENT_NULL);
Yuta HIGUCHI4f8a3772017-05-16 20:23:49 -0700268 IntentData data = IntentData.purge(intent);
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700269 store.addPending(data);
helenyrwu2a674902016-07-20 09:48:04 -0700270
271 // remove associated group if there is one
272 if (intent instanceof PointToPointIntent) {
273 PointToPointIntent pointIntent = (PointToPointIntent) intent;
Ray Milkeya2cf3a12018-02-15 16:13:56 -0800274 DeviceId deviceId = pointIntent.filteredIngressPoint().connectPoint().deviceId();
helenyrwu2a674902016-07-20 09:48:04 -0700275 GroupKey groupKey = PointToPointIntentCompiler.makeGroupKey(intent.id());
276 groupService.removeGroup(deviceId, groupKey,
277 intent.appId());
278 }
Ray Milkey8c6d00e2015-03-13 14:14:34 -0700279 }
280
281 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800282 public Intent getIntent(Key key) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900283 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800284 return store.getIntent(key);
285 }
286
287 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700288 public Iterable<Intent> getIntents() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900289 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700290 return store.getIntents();
291 }
292
293 @Override
Brian O'Connor38224302016-08-02 22:03:01 -0700294 public void addPending(IntentData intentData) {
295 checkPermission(INTENT_WRITE);
296 checkNotNull(intentData, INTENT_NULL);
297 //TODO we might consider further checking / assertions
298 store.addPending(intentData);
299 }
300
301 @Override
Thomas Vachuskac46af202015-06-03 16:43:27 -0700302 public Iterable<IntentData> getIntentData() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900303 checkPermission(INTENT_READ);
Thomas Vachuskac46af202015-06-03 16:43:27 -0700304 return store.getIntentData(false, 0);
305 }
306
307 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700308 public long getIntentCount() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900309 checkPermission(INTENT_READ);
Brian O'Connor66630c82014-10-02 21:08:19 -0700310 return store.getIntentCount();
311 }
312
313 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800314 public IntentState getIntentState(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900315 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800316 checkNotNull(intentKey, INTENT_ID_NULL);
317 return store.getIntentState(intentKey);
Brian O'Connor66630c82014-10-02 21:08:19 -0700318 }
319
320 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800321 public List<Intent> getInstallableIntents(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900322 checkPermission(INTENT_READ);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800323 checkNotNull(intentKey, INTENT_ID_NULL);
324 return store.getInstallableIntents(intentKey);
Thomas Vachuska10d4abc2014-10-21 12:47:26 -0700325 }
326
327 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800328 public boolean isLocal(Key intentKey) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900329 checkPermission(INTENT_READ);
Brian O'Connorbe28a872015-02-19 21:44:37 -0800330 return store.isMaster(intentKey);
331 }
332
333 @Override
Brian O'Connor66630c82014-10-02 21:08:19 -0700334 public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900335 checkPermission(INTENT_WRITE);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800336 compilerRegistry.registerCompiler(cls, compiler);
Brian O'Connor66630c82014-10-02 21:08:19 -0700337 }
338
339 @Override
340 public <T extends Intent> void unregisterCompiler(Class<T> cls) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900341 checkPermission(INTENT_WRITE);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800342 compilerRegistry.unregisterCompiler(cls);
Brian O'Connor66630c82014-10-02 21:08:19 -0700343 }
344
345 @Override
346 public Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> getCompilers() {
Heedo Kang4a47a302016-02-29 17:40:23 +0900347 checkPermission(INTENT_READ);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800348 return compilerRegistry.getCompilers();
Brian O'Connor66630c82014-10-02 21:08:19 -0700349 }
350
351 @Override
Yi Tsengc927a062017-05-02 15:02:37 -0700352 public <T extends Intent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
353 installerRegistry.registerInstaller(cls, installer);
354 }
355
356 @Override
357 public <T extends Intent> void unregisterInstaller(Class<T> cls) {
358 installerRegistry.unregisterInstaller(cls);
359 }
360
361 @Override
362 public Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> getInstallers() {
363 return installerRegistry.getInstallers();
364 }
365
366 @Override
367 @SuppressWarnings("unchecked")
368 public <T extends Intent> IntentInstaller<T> getInstaller(Class<T> cls) {
369 return (IntentInstaller<T>) installerRegistry.getInstallers().get(cls);
370 }
371
372 @Override
Jonathan Hart34f1e382015-02-24 16:52:23 -0800373 public Iterable<Intent> getPending() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900374 checkPermission(INTENT_READ);
Jonathan Hart34f1e382015-02-24 16:52:23 -0800375 return store.getPending();
376 }
377
Yi Tsengc927a062017-05-02 15:02:37 -0700378 @Override
379 public void intentInstallSuccess(IntentOperationContext context) {
380 installCoordinator.success(context);
381 }
382
383 @Override
384 public void intentInstallFailed(IntentOperationContext context) {
385 installCoordinator.failed(context);
386 }
387
Brian O'Connor66630c82014-10-02 21:08:19 -0700388 // Store delegate to re-post events emitted from the store.
389 private class InternalStoreDelegate implements IntentStoreDelegate {
390 @Override
391 public void notify(IntentEvent event) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700392 post(event);
Naoki Shiotabbc7ead2016-01-20 14:10:38 -0800393 switch (event.type()) {
394 case WITHDRAWN:
Luca Pretede10c782017-01-05 17:23:08 -0800395 if (!skipReleaseResourcesOnWithdrawal) {
396 releaseResources(event.subject());
Naoki Shiotabbc7ead2016-01-20 14:10:38 -0800397 }
398 break;
399 default:
400 break;
401 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700402 }
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800403
404 @Override
Brian O'Connorcff03322015-02-03 15:28:59 -0800405 public void process(IntentData data) {
406 accumulator.add(data);
Brian O'Connorea4d7d12015-01-28 16:37:46 -0800407 }
Thomas Vachuskac46af202015-06-03 16:43:27 -0700408
409 @Override
410 public void onUpdate(IntentData intentData) {
411 trackerService.trackIntent(intentData);
412 }
Luca Pretede10c782017-01-05 17:23:08 -0800413
414 private void releaseResources(Intent intent) {
415 // If a resource group is set on the intent, the resource consumer is
416 // set equal to it. Otherwise it's set to the intent key
417 ResourceConsumer resourceConsumer =
418 intent.resourceGroup() != null ? intent.resourceGroup() : intent.key();
419
420 // By default the resource doesn't get released
421 boolean removeResource = false;
422
423 if (intent.resourceGroup() == null) {
424 // If the intent doesn't have a resource group, it means the
425 // resource was registered using the intent key, so it can be
426 // released
427 removeResource = true;
428 } else {
429 // When a resource group is set, we make sure there are no other
430 // intents using the same resource group, before deleting the
431 // related resources.
432 Long remainingIntents =
433 Tools.stream(store.getIntents())
Yi Tseng2ef80142017-02-17 15:56:32 -0800434 .filter(i -> {
435 return i.resourceGroup() != null
436 && i.resourceGroup().equals(intent.resourceGroup());
437 })
Luca Pretede10c782017-01-05 17:23:08 -0800438 .count();
439 if (remainingIntents == 0) {
440 removeResource = true;
441 }
442 }
443
444 if (removeResource) {
445 // Release resources allocated to withdrawn intent
446 if (!resourceService.release(resourceConsumer)) {
447 log.error("Failed to release resources allocated to {}", resourceConsumer);
448 }
449 }
450 }
Brian O'Connor66630c82014-10-02 21:08:19 -0700451 }
452
Sho SHIMIZU4cee50f2016-02-23 16:24:42 -0800453 // Store delegate enabled only when performing intent throughput tests
454 private class TestOnlyIntentStoreDelegate implements IntentStoreDelegate {
455 @Override
456 public void process(IntentData data) {
457 accumulator.add(data);
458 }
459
460 @Override
461 public void onUpdate(IntentData data) {
462 trackerService.trackIntent(data);
463 }
464
465 @Override
466 public void notify(IntentEvent event) {
467 post(event);
468 }
469 }
470
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800471 private void buildAndSubmitBatches(Iterable<Key> intentKeys,
Brian O'Connor72a034c2014-11-26 18:24:23 -0800472 boolean compileAllFailed) {
Brian O'Connor72a034c2014-11-26 18:24:23 -0800473 // Attempt recompilation of the specified intents first.
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800474 for (Key key : intentKeys) {
Yi Tseng49a2b2e2017-05-11 14:32:16 -0700475 if (!store.isMaster(key)) {
476 continue;
477 }
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800478 Intent intent = store.getIntent(key);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800479 if (intent == null) {
480 continue;
481 }
jaegonkimb914fcb2018-05-20 16:04:06 +0900482 if (store.getPendingData(key) != null) {
483 continue;
484 }
Brian O'Connor03406a42015-02-03 17:28:57 -0800485 submit(intent);
Brian O'Connor72a034c2014-11-26 18:24:23 -0800486 }
487
Jonathan Hart0cca3e82015-09-23 17:54:11 -0700488 if (compileAllFailed) {
489 // If required, compile all currently failed intents.
490 for (Intent intent : getIntents()) {
Yi Tseng49a2b2e2017-05-11 14:32:16 -0700491 if (!store.isMaster(intent.key())) {
492 continue;
493 }
jaegonkimb914fcb2018-05-20 16:04:06 +0900494 if (store.getPendingData(intent.key()) != null) {
495 continue;
496 }
Jonathan Hart0cca3e82015-09-23 17:54:11 -0700497 IntentState state = getIntentState(intent.key());
498 if (RECOMPILE.contains(state) || intentAllowsPartialFailure(intent)) {
499 if (WITHDRAW.contains(state)) {
500 withdraw(intent);
501 } else {
502 submit(intent);
503 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800504 }
505 }
506 }
Brian O'Connor72a034c2014-11-26 18:24:23 -0800507 }
508
tom95329eb2014-10-06 08:40:06 -0700509 // Topology change delegate
510 private class InternalTopoChangeDelegate implements TopologyChangeDelegate {
511 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800512 public void triggerCompile(Iterable<Key> intentKeys,
tom85258ee2014-10-07 00:10:02 -0700513 boolean compileAllFailed) {
Yuta HIGUCHI4f8a3772017-05-16 20:23:49 -0700514 // TODO figure out who is making excessive calls?
Jon Hall274cecb2017-08-09 12:15:48 -0700515 log.trace("submitting {} + all?:{} for compilation", intentKeys, compileAllFailed);
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800516 buildAndSubmitBatches(intentKeys, compileAllFailed);
tom95329eb2014-10-06 08:40:06 -0700517 }
tom95329eb2014-10-06 08:40:06 -0700518 }
tom85258ee2014-10-07 00:10:02 -0700519
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700520 private class InternalBatchDelegate implements IntentBatchDelegate {
521 @Override
Brian O'Connorb499b352015-02-03 16:46:15 -0800522 public void execute(Collection<IntentData> operations) {
Brian O'Connorab8ef822015-02-17 18:08:54 -0800523 log.debug("Execute {} operation(s).", operations.size());
524 log.trace("Execute operations: {}", operations);
Sho SHIMIZU94b03b12015-04-10 14:53:13 -0700525
526 // batchExecutor is single-threaded, so only one batch is in flight at a time
Sho SHIMIZU489aa9b2016-01-14 17:19:32 -0800527 CompletableFuture.runAsync(() -> {
Sho SHIMIZU8f2b7772016-01-14 18:17:44 -0800528 // process intent until the phase reaches one of the final phases
529 List<CompletableFuture<IntentData>> futures = operations.stream()
Yuta HIGUCHI4f8a3772017-05-16 20:23:49 -0700530 .map(data -> {
531 log.debug("Start processing of {} {}@{}", data.request(), data.key(), data.version());
532 return data;
533 })
Sho SHIMIZU8f2b7772016-01-14 18:17:44 -0800534 .map(x -> CompletableFuture.completedFuture(x)
535 .thenApply(IntentManager.this::createInitialPhase)
Sho SHIMIZU4a141852016-01-14 18:55:40 -0800536 .thenApplyAsync(IntentProcessPhase::process, workerExecutor)
Sho SHIMIZU8f2b7772016-01-14 18:17:44 -0800537 .thenApply(FinalIntentProcessPhase::data)
538 .exceptionally(e -> {
Pier Luigi13b287f2017-01-10 15:07:52 -0800539 // When the future fails, we update the Intent to simulate the failure of
540 // the installation/withdrawal phase and we save in the current map. In
541 // the next round the CleanUp Thread will pick this Intent again.
542 log.warn("Future failed", e);
543 log.warn("Intent {} - state {} - request {}",
544 x.key(), x.state(), x.request());
545 switch (x.state()) {
546 case INSTALL_REQ:
547 case INSTALLING:
548 case WITHDRAW_REQ:
549 case WITHDRAWING:
Yuta HIGUCHI4f8a3772017-05-16 20:23:49 -0700550 // TODO should we swtich based on current
Pier Luigi13b287f2017-01-10 15:07:52 -0800551 IntentData current = store.getIntentData(x.key());
Yuta HIGUCHI4f8a3772017-05-16 20:23:49 -0700552 return IntentData.nextState(current, FAILED);
Pier Luigi13b287f2017-01-10 15:07:52 -0800553 default:
554 return null;
555 }
Brian O'Connorc590ebb2016-12-08 18:16:41 -0800556 }))
557 .collect(Collectors.toList());
Sho SHIMIZU62bbc602016-01-13 16:54:35 -0800558
Sho SHIMIZU8f2b7772016-01-14 18:17:44 -0800559 // write multiple data to store in order
560 store.batchWrite(Tools.allOf(futures).join().stream()
Thomas Vachuskaf6ec97b2016-02-22 10:59:23 -0800561 .filter(Objects::nonNull)
562 .collect(Collectors.toList()));
Sho SHIMIZU8f2b7772016-01-14 18:17:44 -0800563 }, batchExecutor).exceptionally(e -> {
564 log.error("Error submitting batches:", e);
565 // FIXME incomplete Intents should be cleaned up
566 // (transition to FAILED, etc.)
567
568 // the batch has failed
569 // TODO: maybe we should do more?
570 log.error("Walk the plank, matey...");
Sho SHIMIZU8f2b7772016-01-14 18:17:44 -0800571 return null;
572 }).thenRun(accumulator::ready);
573
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700574 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700575 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800576
Sho SHIMIZUc88b85e2016-01-14 18:45:14 -0800577 private IntentProcessPhase createInitialPhase(IntentData data) {
Brian O'Connorc590ebb2016-12-08 18:16:41 -0800578 IntentData pending = store.getPendingData(data.key());
579 if (pending == null || pending.version().isNewerThan(data.version())) {
580 /*
581 If the pending map is null, then this intent was compiled by a
582 previous batch iteration, so we can skip it.
583 If the pending map has a newer request, it will get compiled as
584 part of the next batch, so we can skip it.
585 */
586 return Skipped.getPhase();
587 }
Sho SHIMIZUc88b85e2016-01-14 18:45:14 -0800588 IntentData current = store.getIntentData(data.key());
589 return newInitialPhase(processor, data, current);
590 }
591
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800592 private class InternalIntentProcessor implements IntentProcessor {
593 @Override
594 public List<Intent> compile(Intent intent, List<Intent> previousInstallables) {
595 return compilerRegistry.compile(intent, previousInstallables);
596 }
597
598 @Override
Brian O'Connorf0c5a052015-04-27 00:34:53 -0700599 public void apply(Optional<IntentData> toUninstall, Optional<IntentData> toInstall) {
Yi Tsengc927a062017-05-02 15:02:37 -0700600 installCoordinator.installIntents(toUninstall, toInstall);
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800601 }
Ray Milkeyfd7931d2015-03-30 13:58:38 -0700602 }
Sho SHIMIZUb0a47d42015-02-19 13:26:30 -0800603
Brian O'Connor66630c82014-10-02 21:08:19 -0700604}