blob: f6d9b514ab2fc6a923ff0f458dc2a90c74ebc1ea [file] [log] [blame]
Thomas Vachuska96d55b12015-05-11 08:52:03 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Thomas Vachuska96d55b12015-05-11 08:52:03 -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 */
Thomas Vachuska4998caa2015-08-26 13:28:38 -070016package org.onosproject.net.config.impl;
Thomas Vachuska96d55b12015-05-11 08:52:03 -070017
Thomas Vachuska0a400ea2015-09-04 11:25:03 -070018import com.fasterxml.jackson.databind.JsonNode;
Thomas Vachuska96d55b12015-05-11 08:52:03 -070019import com.google.common.collect.ImmutableSet;
20import com.google.common.collect.Maps;
21import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
Andrea Campanellae81e9412018-01-16 11:12:20 +010027import org.onosproject.cluster.ClusterService;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070028import org.onosproject.event.AbstractListenerManager;
Ray Milkeya4122362015-08-18 15:19:08 -070029import org.onosproject.net.config.Config;
30import org.onosproject.net.config.ConfigFactory;
31import org.onosproject.net.config.NetworkConfigEvent;
32import org.onosproject.net.config.NetworkConfigListener;
33import org.onosproject.net.config.NetworkConfigRegistry;
34import org.onosproject.net.config.NetworkConfigService;
35import org.onosproject.net.config.NetworkConfigStore;
36import org.onosproject.net.config.NetworkConfigStoreDelegate;
37import org.onosproject.net.config.SubjectFactory;
Thomas Vachuska96d55b12015-05-11 08:52:03 -070038import org.slf4j.Logger;
39import org.slf4j.LoggerFactory;
40
41import java.util.Map;
42import java.util.Objects;
43import java.util.Set;
44
45import static com.google.common.base.Preconditions.checkNotNull;
Heedo Kang4a47a302016-02-29 17:40:23 +090046import static org.onosproject.security.AppGuard.checkPermission;
47import static org.onosproject.security.AppPermission.Type.*;
Thomas Vachuska96d55b12015-05-11 08:52:03 -070048
49/**
50 * Implementation of the network configuration subsystem.
51 */
52@Component(immediate = true)
53@Service
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070054public class NetworkConfigManager
55 extends AbstractListenerManager<NetworkConfigEvent, NetworkConfigListener>
56 implements NetworkConfigRegistry, NetworkConfigService {
Thomas Vachuska96d55b12015-05-11 08:52:03 -070057
58 private final Logger log = LoggerFactory.getLogger(getClass());
59
60 private static final String NULL_FACTORY_MSG = "Factory cannot be null";
61 private static final String NULL_SCLASS_MSG = "Subject class cannot be null";
Simon Hunt3da1a182016-02-08 16:42:54 -080062 private static final String NULL_SCKEY_MSG = "Subject class key cannot be null";
Thomas Vachuska96d55b12015-05-11 08:52:03 -070063 private static final String NULL_CCLASS_MSG = "Config class cannot be null";
Thomas Vachuska6f350ed2016-01-08 09:53:03 -080064 private static final String NULL_CKEY_MSG = "Config key cannot be null";
Thomas Vachuska96d55b12015-05-11 08:52:03 -070065 private static final String NULL_SUBJECT_MSG = "Subject cannot be null";
Thomas Vachuska6f350ed2016-01-08 09:53:03 -080066 private static final String NULL_JSON_MSG = "JSON cannot be null";
Thomas Vachuska96d55b12015-05-11 08:52:03 -070067
68 // Inventory of configuration factories
69 private final Map<ConfigKey, ConfigFactory> factories = Maps.newConcurrentMap();
ke han31dd5b42017-06-23 13:35:09 +080070 private final Map<ConfigKey, Integer> factoryCounters = Maps.newConcurrentMap();
Thomas Vachuska96d55b12015-05-11 08:52:03 -070071
Ray Milkey0a4f6c32015-08-03 11:22:01 -070072 // Secondary indices to retrieve subject and config classes by keys
Thomas Vachuska96d55b12015-05-11 08:52:03 -070073 private final Map<String, SubjectFactory> subjectClasses = Maps.newConcurrentMap();
74 private final Map<Class, SubjectFactory> subjectClassKeys = Maps.newConcurrentMap();
Jonathan Hart111b42b2015-07-14 13:28:05 -070075 private final Map<ConfigIdentifier, Class<? extends Config>> configClasses = Maps.newConcurrentMap();
Thomas Vachuska96d55b12015-05-11 08:52:03 -070076
Thomas Vachuska96d55b12015-05-11 08:52:03 -070077 private final NetworkConfigStoreDelegate storeDelegate = new InternalStoreDelegate();
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected NetworkConfigStore store;
81
Andrea Campanellae81e9412018-01-16 11:12:20 +010082 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected ClusterService clusterService;
84
Thomas Vachuska96d55b12015-05-11 08:52:03 -070085
86 @Activate
87 public void activate() {
88 eventDispatcher.addSink(NetworkConfigEvent.class, listenerRegistry);
89 store.setDelegate(storeDelegate);
90 log.info("Started");
91 }
92
93 @Deactivate
94 public void deactivate() {
95 eventDispatcher.removeSink(NetworkConfigEvent.class);
96 store.unsetDelegate(storeDelegate);
97 log.info("Stopped");
98 }
99
100
101 @Override
102 @SuppressWarnings("unchecked")
103 public void registerConfigFactory(ConfigFactory configFactory) {
104 checkNotNull(configFactory, NULL_FACTORY_MSG);
ke han31dd5b42017-06-23 13:35:09 +0800105 if (factoryCounters.containsKey(key(configFactory))) {
106 factoryCounters.replace(key(configFactory), (factoryCounters.get(key(configFactory)) + 1));
107 } else {
108 factories.put(key(configFactory), configFactory);
109 factoryCounters.put(key(configFactory), 1);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700110
ke han31dd5b42017-06-23 13:35:09 +0800111 configClasses.put(identifier(configFactory), configFactory.configClass());
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700112
ke han31dd5b42017-06-23 13:35:09 +0800113 SubjectFactory subjectFactory = configFactory.subjectFactory();
114 subjectClasses.putIfAbsent(subjectFactory.subjectClassKey(), subjectFactory);
115 subjectClassKeys.putIfAbsent(subjectFactory.subjectClass(), subjectFactory);
116
117 store.addConfigFactory(configFactory);
118 }
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700119 }
120
121 @Override
122 public void unregisterConfigFactory(ConfigFactory configFactory) {
123 checkNotNull(configFactory, NULL_FACTORY_MSG);
ke han31dd5b42017-06-23 13:35:09 +0800124 Integer factoryCounter = factoryCounters.get(key(configFactory));
125 if (factoryCounter > 1) {
126 factoryCounters.replace(key(configFactory), (factoryCounter - 1));
127 } else {
128 factoryCounters.remove(key(configFactory));
129 factories.remove(key(configFactory));
130 configClasses.remove(identifier(configFactory));
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700131
Andrea Campanellae81e9412018-01-16 11:12:20 +0100132 // Removing the config factory only if this is the only ONOS instance or if it's the last
133 // instance active in a cluster. otherwise the other instances lose access to the config factory
134 // and can't use the associated net-cfgs.
135 if (clusterService.getNodes().size() == 1) {
136 // Note that we are deliberately not removing subject factory key bindings.
137 store.removeConfigFactory(configFactory);
138 }
ke han31dd5b42017-06-23 13:35:09 +0800139 }
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700140 }
141
142 @Override
143 public Set<ConfigFactory> getConfigFactories() {
144 return ImmutableSet.copyOf(factories.values());
145 }
146
147
148 @Override
149 @SuppressWarnings("unchecked")
150 public <S, C extends Config<S>> Set<ConfigFactory<S, C>> getConfigFactories(Class<S> subjectClass) {
151 ImmutableSet.Builder<ConfigFactory<S, C>> builder = ImmutableSet.builder();
152 factories.forEach((key, factory) -> {
153 if (factory.subjectFactory().subjectClass().equals(subjectClass)) {
154 builder.add(factory);
155 }
156 });
157 return builder.build();
158 }
159
160 @Override
161 public <S, C extends Config<S>> ConfigFactory<S, C> getConfigFactory(Class<C> configClass) {
162 checkNotNull(configClass, NULL_CCLASS_MSG);
163 return store.getConfigFactory(configClass);
164 }
165
166
167 @Override
168 public Set<Class> getSubjectClasses() {
Heedo Kang4a47a302016-02-29 17:40:23 +0900169 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700170 ImmutableSet.Builder<Class> builder = ImmutableSet.builder();
171 factories.forEach((k, v) -> builder.add(k.subjectClass));
172 return builder.build();
173 }
174
175 @Override
Thomas Vachuskaea5adc62015-10-07 11:52:30 -0700176 public SubjectFactory getSubjectFactory(String subjectClassKey) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900177 checkPermission(CONFIG_READ);
Thomas Vachuskaea5adc62015-10-07 11:52:30 -0700178 return subjectClasses.get(subjectClassKey);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700179 }
180
181 @Override
182 public SubjectFactory getSubjectFactory(Class subjectClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900183 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700184 return subjectClassKeys.get(subjectClass);
185 }
186
187 @Override
Thomas Vachuskaea5adc62015-10-07 11:52:30 -0700188 public Class<? extends Config> getConfigClass(String subjectClassKey, String configKey) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900189 checkPermission(CONFIG_READ);
Simon Hunt3da1a182016-02-08 16:42:54 -0800190 checkNotNull(subjectClassKey, NULL_SCKEY_MSG);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800191 checkNotNull(configKey, NULL_CKEY_MSG);
Thomas Vachuskaea5adc62015-10-07 11:52:30 -0700192 return configClasses.get(new ConfigIdentifier(subjectClassKey, configKey));
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700193 }
194
195 @Override
196 public <S> Set<S> getSubjects(Class<S> subjectClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900197 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700198 checkNotNull(subjectClass, NULL_SCLASS_MSG);
199 return store.getSubjects(subjectClass);
200 }
201
202 @Override
203 public <S, C extends Config<S>> Set<S> getSubjects(Class<S> subjectClass, Class<C> configClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900204 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700205 checkNotNull(subjectClass, NULL_SCLASS_MSG);
206 checkNotNull(configClass, NULL_CCLASS_MSG);
207 return store.getSubjects(subjectClass, configClass);
208 }
209
210 @Override
211 public <S> Set<Config<S>> getConfigs(S subject) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900212 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700213 checkNotNull(subject, NULL_SUBJECT_MSG);
214 Set<Class<? extends Config<S>>> configClasses = store.getConfigClasses(subject);
215 ImmutableSet.Builder<Config<S>> cfg = ImmutableSet.builder();
216 configClasses.forEach(cc -> cfg.add(store.getConfig(subject, cc)));
217 return cfg.build();
218 }
219
220 @Override
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800221 public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900222 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700223 checkNotNull(subject, NULL_SUBJECT_MSG);
224 checkNotNull(configClass, NULL_CCLASS_MSG);
225 return store.getConfig(subject, configClass);
226 }
227
228
229 @Override
230 public <S, C extends Config<S>> C addConfig(S subject, Class<C> configClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900231 checkPermission(CONFIG_WRITE);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700232 checkNotNull(subject, NULL_SUBJECT_MSG);
233 checkNotNull(configClass, NULL_CCLASS_MSG);
234 return store.createConfig(subject, configClass);
235 }
236
237 @Override
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700238 public <S, C extends Config<S>> C applyConfig(S subject, Class<C> configClass, JsonNode json) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900239 checkPermission(CONFIG_WRITE);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700240 checkNotNull(subject, NULL_SUBJECT_MSG);
241 checkNotNull(configClass, NULL_CCLASS_MSG);
Simon Hunt3da1a182016-02-08 16:42:54 -0800242 checkNotNull(json, NULL_JSON_MSG);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700243 return store.applyConfig(subject, configClass, json);
244 }
245
246 @Override
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800247 @SuppressWarnings("unchecked")
248 public <S, C extends Config<S>> C applyConfig(String subjectClassKey, S subject,
249 String configKey, JsonNode json) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900250 checkPermission(CONFIG_WRITE);
Simon Hunt3da1a182016-02-08 16:42:54 -0800251 checkNotNull(subjectClassKey, NULL_SCKEY_MSG);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800252 checkNotNull(subject, NULL_SUBJECT_MSG);
253 checkNotNull(configKey, NULL_CKEY_MSG);
Simon Hunt3da1a182016-02-08 16:42:54 -0800254 checkNotNull(json, NULL_JSON_MSG);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800255 Class<? extends Config> configClass = configClasses.get(new ConfigIdentifier(subjectClassKey, configKey));
256 if (configClass != null) {
257 return store.applyConfig(subject, (Class<C>) configClass, json);
258 } else {
Andrea Campanelladcb5e932016-01-11 17:32:23 -0800259 log.info("Configuration \'{}\' queued for subject {}", configKey, subject);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800260 store.queueConfig(subject, configKey, json);
261 return null;
262 }
263 }
264
265 @Override
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700266 public <S, C extends Config<S>> void removeConfig(S subject, Class<C> configClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900267 checkPermission(CONFIG_WRITE);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700268 checkNotNull(subject, NULL_SUBJECT_MSG);
269 checkNotNull(configClass, NULL_CCLASS_MSG);
270 store.clearConfig(subject, configClass);
271 }
272
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800273 @Override
274 public <S> void removeConfig(String subjectClassKey, S subject, String configKey) {
Simon Hunt3da1a182016-02-08 16:42:54 -0800275 checkNotNull(subjectClassKey, NULL_SCKEY_MSG);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800276 checkNotNull(subject, NULL_SUBJECT_MSG);
Simon Hunt3da1a182016-02-08 16:42:54 -0800277 checkNotNull(configKey, NULL_CKEY_MSG);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800278 Class<? extends Config> configClass = configClasses.get(new ConfigIdentifier(subjectClassKey, configKey));
279 if (configClass != null) {
280 store.clearConfig(subject, configClass);
281 } else {
282 store.clearQueuedConfig(subject, configKey);
Andrea Campanellae81e9412018-01-16 11:12:20 +0100283 }
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800284 }
285
Andrea Campanellae81e9412018-01-16 11:12:20 +0100286 @Override
287 public <S> void removeConfig(S subject) {
Deepa Vaddireddy0c49b602016-06-02 12:19:07 +0530288 checkPermission(CONFIG_WRITE);
289 store.clearConfig(subject);
Andrea Campanellae81e9412018-01-16 11:12:20 +0100290 }
Deepa Vaddireddy0c49b602016-06-02 12:19:07 +0530291
Andrea Campanellae81e9412018-01-16 11:12:20 +0100292 @Override
293 public <S> void removeConfig() {
294 checkPermission(CONFIG_WRITE);
295 store.clearConfig();
296 }
Deepa Vaddireddy0c49b602016-06-02 12:19:07 +0530297
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700298 // Auxiliary store delegate to receive notification about changes in
299 // the network configuration store state - by the store itself.
300 private class InternalStoreDelegate implements NetworkConfigStoreDelegate {
301 @Override
302 public void notify(NetworkConfigEvent event) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700303 post(event);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700304 }
305 }
306
307
308 // Produces a key for uniquely tracking a config factory.
309 private static ConfigKey key(ConfigFactory factory) {
310 return new ConfigKey(factory.subjectFactory().subjectClass(), factory.configClass());
311 }
312
313 // Auxiliary key to track config factories.
Ray Milkeyae9faf12015-08-03 15:52:26 -0700314 protected static final class ConfigKey {
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700315 final Class subjectClass;
316 final Class configClass;
317
Ray Milkeyae9faf12015-08-03 15:52:26 -0700318 protected ConfigKey(Class subjectClass, Class configClass) {
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700319 this.subjectClass = subjectClass;
320 this.configClass = configClass;
321 }
322
323 @Override
324 public int hashCode() {
325 return Objects.hash(subjectClass, configClass);
326 }
327
328 @Override
329 public boolean equals(Object obj) {
330 if (this == obj) {
331 return true;
332 }
333 if (obj instanceof ConfigKey) {
334 final ConfigKey other = (ConfigKey) obj;
335 return Objects.equals(this.subjectClass, other.subjectClass)
336 && Objects.equals(this.configClass, other.configClass);
337 }
338 return false;
339 }
340 }
341
Jonathan Hart111b42b2015-07-14 13:28:05 -0700342 private static ConfigIdentifier identifier(ConfigFactory factory) {
Thomas Vachuskaea5adc62015-10-07 11:52:30 -0700343 return new ConfigIdentifier(factory.subjectFactory().subjectClassKey(), factory.configKey());
Jonathan Hart111b42b2015-07-14 13:28:05 -0700344 }
345
Thomas Vachuska4998caa2015-08-26 13:28:38 -0700346 static final class ConfigIdentifier {
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800347 final String subjectClassKey;
Jonathan Hart111b42b2015-07-14 13:28:05 -0700348 final String configKey;
349
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800350 protected ConfigIdentifier(String subjectClassKey, String configKey) {
351 this.subjectClassKey = subjectClassKey;
Jonathan Hart111b42b2015-07-14 13:28:05 -0700352 this.configKey = configKey;
353 }
354
355 @Override
356 public int hashCode() {
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800357 return Objects.hash(subjectClassKey, configKey);
Jonathan Hart111b42b2015-07-14 13:28:05 -0700358 }
359
360 @Override
361 public boolean equals(Object obj) {
362 if (this == obj) {
363 return true;
364 }
365 if (obj instanceof ConfigIdentifier) {
366 final ConfigIdentifier other = (ConfigIdentifier) obj;
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800367 return Objects.equals(this.subjectClassKey, other.subjectClassKey)
Jonathan Hart111b42b2015-07-14 13:28:05 -0700368 && Objects.equals(this.configKey, other.configKey);
369 }
370 return false;
371 }
372 }
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800373
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700374}