blob: 4a0925031fe7d207a8a0626f8795f38daea3d98c [file] [log] [blame]
Yoonseon Han096cea02017-05-15 15:10:41 -07001/*
2 * Copyright 2017-present Open Networking Foundation
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 */
16
17package org.onosproject.incubator.net.virtual.impl.intent;
18
19import com.google.common.collect.ArrayListMultimap;
20import com.google.common.collect.Maps;
21import com.google.common.collect.Sets;
22import org.onosproject.incubator.net.virtual.NetworkId;
23import org.onosproject.incubator.net.virtual.VirtualNetworkIntentStore;
24import org.onosproject.incubator.net.virtual.impl.VirtualNetworkIntentManager;
25import org.onosproject.net.intent.Intent;
26import org.onosproject.net.intent.IntentData;
27import org.onosproject.net.intent.IntentInstallationContext;
28import org.onosproject.net.intent.IntentInstaller;
29import org.onosproject.net.intent.IntentOperationContext;
30import org.slf4j.Logger;
31
32import java.util.Collections;
33import java.util.List;
34import java.util.Map;
35import java.util.Optional;
36import java.util.Set;
37
38import static org.onosproject.net.intent.IntentState.*;
39import static org.slf4j.LoggerFactory.getLogger;
40
41/**
42 * Implementation of IntentInstallCoordinator for virtual network.
43 */
44public class VirtualIntentInstallCoordinator {
45 private static final String INSTALLER_NOT_FOUND = "Intent installer not found, Intent: {}";
46 private final Logger log = getLogger(VirtualNetworkIntentManager.class);
47
48 NetworkId networkId;
49 private VirtualIntentInstallerRegistry installerRegistry;
50 private VirtualNetworkIntentStore intentStore;
51
52 /**
53 * Creates an InstallCoordinator.
54 *
55 * @param networkId virtual network identifier
56 * @param installerRegistry the installer registry
57 * @param intentStore the Intent store
58 */
59 public VirtualIntentInstallCoordinator(NetworkId networkId,
60 VirtualIntentInstallerRegistry installerRegistry,
61 VirtualNetworkIntentStore intentStore) {
62 this.networkId = networkId;
63 this.installerRegistry = installerRegistry;
64 this.intentStore = intentStore;
65 }
66
67 /**
68 * Applies Intent data to be uninstalled and to be installed.
69 *
70 * @param toUninstall Intent data to be uninstalled
71 * @param toInstall Intent data to be installed
72 */
73 public void installIntents(Optional<IntentData> toUninstall,
74 Optional<IntentData> toInstall) {
75 // If no any Intents to be uninstalled or installed, ignore it.
76 if (!toUninstall.isPresent() && !toInstall.isPresent()) {
77 return;
78 }
79
80 // Classify installable Intents to different installers.
81 ArrayListMultimap<IntentInstaller, Intent> uninstallInstallers;
82 ArrayListMultimap<IntentInstaller, Intent> installInstallers;
83 Set<IntentInstaller> allInstallers = Sets.newHashSet();
84
85 if (toUninstall.isPresent()) {
86 uninstallInstallers = getInstallers(toUninstall.get());
87 allInstallers.addAll(uninstallInstallers.keySet());
88 } else {
89 uninstallInstallers = ArrayListMultimap.create();
90 }
91
92 if (toInstall.isPresent()) {
93 installInstallers = getInstallers(toInstall.get());
94 allInstallers.addAll(installInstallers.keySet());
95 } else {
96 installInstallers = ArrayListMultimap.create();
97 }
98
99 // Generates an installation context for the high level Intent.
100 IntentInstallationContext installationContext =
101 new IntentInstallationContext(toUninstall.orElse(null), toInstall.orElse(null));
102
103 //Generates different operation context for different installable Intents.
104 Map<IntentInstaller, IntentOperationContext> contexts = Maps.newHashMap();
105 allInstallers.forEach(installer -> {
106 List<Intent> intentsToUninstall = uninstallInstallers.get(installer);
107 List<Intent> intentsToInstall = installInstallers.get(installer);
108
109 // Connect context to high level installation context
110 IntentOperationContext context =
111 new IntentOperationContext(intentsToUninstall, intentsToInstall,
112 installationContext);
113 installationContext.addPendingContext(context);
114 contexts.put(installer, context);
115 });
116
117 // Apply contexts to installers
118 contexts.forEach((installer, context) -> {
119 installer.apply(context);
120 });
121 }
122
123 /**
124 * Generates a mapping for installable Intents to installers.
125 *
126 * @param intentData the Intent data which contains installable Intents
127 * @return the mapping for installable Intents to installers
128 */
129 private ArrayListMultimap<IntentInstaller, Intent> getInstallers(IntentData intentData) {
130 ArrayListMultimap<IntentInstaller, Intent> intentInstallers = ArrayListMultimap.create();
131 intentData.installables().forEach(intent -> {
132 IntentInstaller installer = installerRegistry.getInstaller(intent.getClass());
133 if (installer != null) {
134 intentInstallers.put(installer, intent);
135 } else {
136 log.warn(INSTALLER_NOT_FOUND, intent);
137 }
138 });
139 return intentInstallers;
140 }
141
142 /**
143 * Handles success operation context.
144 *
145 * @param context the operation context
146 */
147 public void success(IntentOperationContext context) {
148 IntentInstallationContext intentInstallationContext =
149 context.intentInstallationContext();
150 intentInstallationContext.removePendingContext(context);
151
152 if (intentInstallationContext.isPendingContextsEmpty()) {
153 finish(intentInstallationContext);
154 }
155 }
156
157 /**
158 * Handles failed operation context.
159 *
160 * @param context the operation context
161 */
162 public void failed(IntentOperationContext context) {
163 IntentInstallationContext intentInstallationContext =
164 context.intentInstallationContext();
165 intentInstallationContext.addErrorContext(context);
166 intentInstallationContext.removePendingContext(context);
167
168 if (intentInstallationContext.isPendingContextsEmpty()) {
169 finish(intentInstallationContext);
170 }
171 }
172
173 /**
174 * Completed the installation context and update the Intent store.
175 *
176 * @param intentInstallationContext the installation context
177 */
178 private void finish(IntentInstallationContext intentInstallationContext) {
179 Set<IntentOperationContext> errCtxs = intentInstallationContext.errorContexts();
180 Optional<IntentData> toUninstall = intentInstallationContext.toUninstall();
181 Optional<IntentData> toInstall = intentInstallationContext.toInstall();
182
183 // Intent install success
184 if (errCtxs == null || errCtxs.isEmpty()) {
185 if (toInstall.isPresent()) {
186 IntentData installData = toInstall.get();
187 log.debug("Completed installing: {}", installData.key());
188 installData = new IntentData(installData, installData.installables());
189 installData.setState(INSTALLED);
190 intentStore.write(networkId, installData);
191 } else if (toUninstall.isPresent()) {
192 IntentData uninstallData = toUninstall.get();
193 uninstallData = new IntentData(uninstallData, Collections.emptyList());
194 log.debug("Completed withdrawing: {}", uninstallData.key());
195 switch (uninstallData.request()) {
196 case INSTALL_REQ:
197 log.warn("{} was requested to withdraw during installation?",
198 uninstallData.intent());
199 uninstallData.setState(FAILED);
200 break;
201 case WITHDRAW_REQ:
202 default: //TODO "default" case should not happen
203 uninstallData.setState(WITHDRAWN);
204 break;
205 }
206 // Intent has been withdrawn; we can clear the installables
207 intentStore.write(networkId, uninstallData);
208 }
209 } else {
210 // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT)
211 if (toInstall.isPresent()) {
212 IntentData installData = toInstall.get();
213 installData.setState(CORRUPT);
214 installData.incrementErrorCount();
215 intentStore.write(networkId, installData);
216 }
217 // if toUninstall was cause of error, then CORRUPT (another job will clean this up)
218 if (toUninstall.isPresent()) {
219 IntentData uninstallData = toUninstall.get();
220 uninstallData.setState(CORRUPT);
221 uninstallData.incrementErrorCount();
222 intentStore.write(networkId, uninstallData);
223 }
224 }
225 }
226}