blob: 451394524e2d30ea53cd83f99ac9136f151920fd [file] [log] [blame]
Yi Tsengc927a062017-05-02 15:02:37 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Yi Tsengc927a062017-05-02 15:02:37 -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 */
16
17package org.onosproject.net.intent.impl.installer;
18
19import com.google.common.collect.ImmutableSet;
20import com.google.common.collect.Sets;
21import org.apache.commons.lang3.tuple.Pair;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070022import org.osgi.service.component.annotations.Activate;
23import org.osgi.service.component.annotations.Component;
24import org.osgi.service.component.annotations.Deactivate;
25import org.osgi.service.component.annotations.Reference;
26import org.osgi.service.component.annotations.ReferenceCardinality;
Yi Tsengc927a062017-05-02 15:02:37 -070027import org.onosproject.net.DeviceId;
28import org.onosproject.net.behaviour.protection.ProtectedTransportEndpointDescription;
29import org.onosproject.net.behaviour.protection.ProtectionConfig;
30import org.onosproject.net.config.NetworkConfigEvent;
31import org.onosproject.net.config.NetworkConfigListener;
32import org.onosproject.net.config.NetworkConfigService;
33import org.onosproject.net.intent.IntentData;
34import org.onosproject.net.intent.IntentException;
35import org.onosproject.net.intent.IntentExtensionService;
36import org.onosproject.net.intent.IntentInstallCoordinator;
37import org.onosproject.net.intent.IntentOperationContext;
38import org.onosproject.net.intent.IntentInstaller;
39import org.onosproject.net.intent.ProtectionEndpointIntent;
40import org.onosproject.net.intent.impl.IntentManager;
Yi Tseng24d9be72017-05-12 11:28:13 -070041import org.onosproject.net.intent.ObjectiveTrackerService;
Yi Tsengc927a062017-05-02 15:02:37 -070042import org.slf4j.Logger;
43
44import java.util.ArrayList;
45import java.util.Collection;
46import java.util.List;
47import java.util.Optional;
48import java.util.Set;
49import java.util.concurrent.CompletableFuture;
50import java.util.concurrent.ExecutionException;
51import java.util.concurrent.TimeUnit;
52import java.util.concurrent.TimeoutException;
53import java.util.stream.Collectors;
54
55import static com.google.common.base.Preconditions.checkNotNull;
56import static org.onosproject.net.config.NetworkConfigEvent.Type.*;
57import static org.onosproject.net.intent.IntentInstaller.Direction.ADD;
58import static org.onosproject.net.intent.IntentInstaller.Direction.REMOVE;
59import static org.slf4j.LoggerFactory.getLogger;
60
61/**
62 * Installer for ProtectionEndpointIntent.
63 */
64@Component(immediate = true)
65public class ProtectionEndpointIntentInstaller implements IntentInstaller<ProtectionEndpointIntent> {
66 private static final String CONFIG_FAILED = "Config operation unsuccessful, expected %s, actual %s.";
67 private final Logger log = getLogger(IntentManager.class);
68
Ray Milkeyd84f89b2018-08-17 14:54:17 -070069 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengc927a062017-05-02 15:02:37 -070070 protected IntentExtensionService intentExtensionService;
71
Ray Milkeyd84f89b2018-08-17 14:54:17 -070072 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengc927a062017-05-02 15:02:37 -070073 NetworkConfigService networkConfigService;
74
Ray Milkeyd84f89b2018-08-17 14:54:17 -070075 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengc927a062017-05-02 15:02:37 -070076 IntentInstallCoordinator intentInstallCoordinator;
77
Ray Milkeyd84f89b2018-08-17 14:54:17 -070078 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Yi Tsengc927a062017-05-02 15:02:37 -070079 ObjectiveTrackerService trackerService;
80
81 @Activate
82 public void activate() {
83 intentExtensionService.registerInstaller(ProtectionEndpointIntent.class, this);
84 }
85
86 @Deactivate
87 public void deactivated() {
88 intentExtensionService.unregisterInstaller(ProtectionEndpointIntent.class);
89 }
90
91 @Override
92 public void apply(IntentOperationContext<ProtectionEndpointIntent> context) {
93 Optional<IntentData> toUninstall = context.toUninstall();
94 Optional<IntentData> toInstall = context.toInstall();
95
96 List<ProtectionEndpointIntent> uninstallIntents = context.intentsToUninstall();
97 List<ProtectionEndpointIntent> installIntents = context.intentsToInstall();
98
99 if (!toInstall.isPresent() && !toUninstall.isPresent()) {
100 intentInstallCoordinator.intentInstallSuccess(context);
101 return;
102 }
103
104 if (toUninstall.isPresent()) {
105 IntentData intentData = toUninstall.get();
106 trackerService.removeTrackedResources(intentData.key(), intentData.intent().resources());
107 uninstallIntents.forEach(installable ->
108 trackerService.removeTrackedResources(intentData.intent().key(),
109 installable.resources()));
110 }
111
112 if (toInstall.isPresent()) {
113 IntentData intentData = toInstall.get();
114 trackerService.addTrackedResources(intentData.key(), intentData.intent().resources());
115 installIntents.forEach(installable ->
116 trackerService.addTrackedResources(intentData.key(),
117 installable.resources()));
118 }
119
120 List<Stage> stages = new ArrayList<>();
121
122 stages.add(new Stage(uninstallIntents.stream()
123 .map(i -> Pair.of(i, REMOVE))
124 .collect(Collectors.toList())));
125
126 stages.add(new Stage(installIntents.stream()
127 .map(i -> Pair.of(i, ADD))
128 .collect(Collectors.toList())));
129 for (Stage stage : stages) {
130 log.debug("applying Stage {}", stage);
131 try {
132 // wait for stage completion
133 stage.apply();
134 stage.listeners().forEach(networkConfigService::removeListener);
135 } catch (IntentException e) {
136 log.error("Stage {} failed, reason: {}", stage, e.toString());
137 intentInstallCoordinator.intentInstallFailed(context);
138 return;
139 }
140 }
141 // All stage success
142 intentInstallCoordinator.intentInstallSuccess(context);
143 }
144
145 /**
146 * Stage of installable Intents which can be processed in parallel.
147 */
148 private final class Stage {
149 // should it have progress state, how far it went?
150 private final Collection<Pair<ProtectionEndpointIntent, Direction>> ops;
151 private final Set<NetworkConfigListener> listeners = Sets.newHashSet();
152
153 /**
154 * Create a stage with given operations.
155 *
156 * @param ops the operations
157 */
158 Stage(Collection<Pair<ProtectionEndpointIntent, Direction>> ops) {
159 this.ops = checkNotNull(ops);
160 }
161
162 /**
163 * Applies all operations for this stage.
164 *
165 * @return the CompletableFuture object for this operation
166 */
167 void apply() {
168 ops.stream()
169 .map(op -> applyOp(op.getRight(), op.getLeft()))
170 .forEach(future -> {
171 try {
172 future.get(100, TimeUnit.MILLISECONDS);
173 } catch (TimeoutException | InterruptedException | ExecutionException e) {
174 throw new IntentException(e.toString());
175 }
176 });
177 }
178
179 /**
180 * Applies the protection endpoint Intent with a given direction.
181 *
182 * @param dir the direction
183 * @param intent the protection endpoint Intent
184 * @return the CompletableFuture object for this operation
185 */
186 private CompletableFuture<Void> applyOp(Direction dir, ProtectionEndpointIntent intent) {
187 log.trace("applying {}: {}", dir, intent);
188 if (dir == REMOVE) {
189 ProtectionConfigListener listener =
190 new ProtectionConfigListener(ImmutableSet.of(CONFIG_REMOVED),
191 intent.deviceId());
192 networkConfigService.addListener(listener);
193 listeners.add(listener);
194 networkConfigService.removeConfig(intent.deviceId(), ProtectionConfig.class);
195 return listener.completableFuture();
196 } else {
197 ProtectedTransportEndpointDescription description = intent.description();
198
199 // Can't do following. Will trigger empty CONFIG_ADDED
200 //ProtectionConfig cfg = networkConfigService.addConfig(intent.deviceId(),
201 // ProtectionConfig.class);
202 ProtectionConfig cfg = new ProtectionConfig(intent.deviceId());
203 cfg.fingerprint(description.fingerprint());
204 cfg.peer(description.peer());
205 cfg.paths(description.paths());
206 ProtectionConfigListener listener =
207 new ProtectionConfigListener(ImmutableSet.of(CONFIG_ADDED, CONFIG_UPDATED),
208 intent.deviceId());
209
210 networkConfigService.addListener(listener);
211 listeners.add(listener);
212 networkConfigService.applyConfig(intent.deviceId(),
213 ProtectionConfig.class,
214 cfg.node());
215 return listener.completableFuture();
216 }
217 }
218
219 @Override
220 public String toString() {
221 return ops.toString();
222 }
223
224 public Set<NetworkConfigListener> listeners() {
225 return listeners;
226 }
227
228 /**
229 * Listener for protection config for specific config event and device.
230 */
231 class ProtectionConfigListener implements NetworkConfigListener {
232 private CompletableFuture<Void> completableFuture;
233 private Set<NetworkConfigEvent.Type> listenTypes;
234 private DeviceId listenDevice;
235
236 public ProtectionConfigListener(Set<NetworkConfigEvent.Type> listenTypes, DeviceId listenDevice) {
237 completableFuture = new CompletableFuture<>();
238 this.listenTypes = listenTypes;
239 this.listenDevice = listenDevice;
240 }
241
242 @Override
243 public void event(NetworkConfigEvent event) {
244 if (!event.subject().equals(listenDevice)) {
245 return;
246 }
247 if (!listenTypes.contains(event.type())) {
248 String errorMsg = String.format(CONFIG_FAILED, listenTypes.toString(), event.type());
249 completableFuture.completeExceptionally(new IntentException(errorMsg));
250 } else {
251 completableFuture.complete(null);
252 }
253 }
254
255 public CompletableFuture<Void> completableFuture() {
256 return completableFuture;
257 }
258 }
259 }
260}