blob: 990f43c81eedadef4b66f9fe28d4e00ac69bd3ee [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;
Andrea Campanellae81e9412018-01-16 11:12:20 +010021import org.onosproject.cluster.ClusterService;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070022import org.onosproject.event.AbstractListenerManager;
Ray Milkeya4122362015-08-18 15:19:08 -070023import org.onosproject.net.config.Config;
24import org.onosproject.net.config.ConfigFactory;
25import org.onosproject.net.config.NetworkConfigEvent;
26import org.onosproject.net.config.NetworkConfigListener;
27import org.onosproject.net.config.NetworkConfigRegistry;
28import org.onosproject.net.config.NetworkConfigService;
29import org.onosproject.net.config.NetworkConfigStore;
30import org.onosproject.net.config.NetworkConfigStoreDelegate;
31import org.onosproject.net.config.SubjectFactory;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070032import org.osgi.service.component.annotations.Activate;
33import org.osgi.service.component.annotations.Component;
34import org.osgi.service.component.annotations.Deactivate;
35import org.osgi.service.component.annotations.Reference;
36import org.osgi.service.component.annotations.ReferenceCardinality;
Thomas Vachuska96d55b12015-05-11 08:52:03 -070037import org.slf4j.Logger;
38import org.slf4j.LoggerFactory;
39
40import java.util.Map;
41import java.util.Objects;
42import java.util.Set;
43
44import static com.google.common.base.Preconditions.checkNotNull;
Heedo Kang4a47a302016-02-29 17:40:23 +090045import static org.onosproject.security.AppGuard.checkPermission;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070046import static org.onosproject.security.AppPermission.Type.CONFIG_READ;
47import static org.onosproject.security.AppPermission.Type.CONFIG_WRITE;
Thomas Vachuska96d55b12015-05-11 08:52:03 -070048
49/**
50 * Implementation of the network configuration subsystem.
51 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070052@Component(immediate = true, service = { NetworkConfigRegistry.class, NetworkConfigService.class })
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070053public class NetworkConfigManager
54 extends AbstractListenerManager<NetworkConfigEvent, NetworkConfigListener>
55 implements NetworkConfigRegistry, NetworkConfigService {
Thomas Vachuska96d55b12015-05-11 08:52:03 -070056
57 private final Logger log = LoggerFactory.getLogger(getClass());
58
59 private static final String NULL_FACTORY_MSG = "Factory cannot be null";
60 private static final String NULL_SCLASS_MSG = "Subject class cannot be null";
Simon Hunt3da1a182016-02-08 16:42:54 -080061 private static final String NULL_SCKEY_MSG = "Subject class key cannot be null";
Thomas Vachuska96d55b12015-05-11 08:52:03 -070062 private static final String NULL_CCLASS_MSG = "Config class cannot be null";
Thomas Vachuska6f350ed2016-01-08 09:53:03 -080063 private static final String NULL_CKEY_MSG = "Config key cannot be null";
Thomas Vachuska96d55b12015-05-11 08:52:03 -070064 private static final String NULL_SUBJECT_MSG = "Subject cannot be null";
Thomas Vachuska6f350ed2016-01-08 09:53:03 -080065 private static final String NULL_JSON_MSG = "JSON cannot be null";
Thomas Vachuska96d55b12015-05-11 08:52:03 -070066
67 // Inventory of configuration factories
68 private final Map<ConfigKey, ConfigFactory> factories = Maps.newConcurrentMap();
ke han31dd5b42017-06-23 13:35:09 +080069 private final Map<ConfigKey, Integer> factoryCounters = Maps.newConcurrentMap();
Thomas Vachuska96d55b12015-05-11 08:52:03 -070070
Ray Milkey0a4f6c32015-08-03 11:22:01 -070071 // Secondary indices to retrieve subject and config classes by keys
Thomas Vachuska96d55b12015-05-11 08:52:03 -070072 private final Map<String, SubjectFactory> subjectClasses = Maps.newConcurrentMap();
73 private final Map<Class, SubjectFactory> subjectClassKeys = Maps.newConcurrentMap();
Jonathan Hart111b42b2015-07-14 13:28:05 -070074 private final Map<ConfigIdentifier, Class<? extends Config>> configClasses = Maps.newConcurrentMap();
Thomas Vachuska96d55b12015-05-11 08:52:03 -070075
Thomas Vachuska96d55b12015-05-11 08:52:03 -070076 private final NetworkConfigStoreDelegate storeDelegate = new InternalStoreDelegate();
77
Ray Milkeyd84f89b2018-08-17 14:54:17 -070078 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska96d55b12015-05-11 08:52:03 -070079 protected NetworkConfigStore store;
80
Ray Milkeyd84f89b2018-08-17 14:54:17 -070081 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellae81e9412018-01-16 11:12:20 +010082 protected ClusterService clusterService;
83
Thomas Vachuska96d55b12015-05-11 08:52:03 -070084
85 @Activate
86 public void activate() {
87 eventDispatcher.addSink(NetworkConfigEvent.class, listenerRegistry);
88 store.setDelegate(storeDelegate);
89 log.info("Started");
90 }
91
92 @Deactivate
93 public void deactivate() {
94 eventDispatcher.removeSink(NetworkConfigEvent.class);
95 store.unsetDelegate(storeDelegate);
96 log.info("Stopped");
97 }
98
99
100 @Override
101 @SuppressWarnings("unchecked")
102 public void registerConfigFactory(ConfigFactory configFactory) {
103 checkNotNull(configFactory, NULL_FACTORY_MSG);
ke han31dd5b42017-06-23 13:35:09 +0800104 if (factoryCounters.containsKey(key(configFactory))) {
105 factoryCounters.replace(key(configFactory), (factoryCounters.get(key(configFactory)) + 1));
106 } else {
107 factories.put(key(configFactory), configFactory);
108 factoryCounters.put(key(configFactory), 1);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700109
ke han31dd5b42017-06-23 13:35:09 +0800110 configClasses.put(identifier(configFactory), configFactory.configClass());
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700111
ke han31dd5b42017-06-23 13:35:09 +0800112 SubjectFactory subjectFactory = configFactory.subjectFactory();
113 subjectClasses.putIfAbsent(subjectFactory.subjectClassKey(), subjectFactory);
114 subjectClassKeys.putIfAbsent(subjectFactory.subjectClass(), subjectFactory);
115
116 store.addConfigFactory(configFactory);
117 }
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700118 }
119
120 @Override
121 public void unregisterConfigFactory(ConfigFactory configFactory) {
122 checkNotNull(configFactory, NULL_FACTORY_MSG);
ke han31dd5b42017-06-23 13:35:09 +0800123 Integer factoryCounter = factoryCounters.get(key(configFactory));
124 if (factoryCounter > 1) {
125 factoryCounters.replace(key(configFactory), (factoryCounter - 1));
126 } else {
127 factoryCounters.remove(key(configFactory));
128 factories.remove(key(configFactory));
129 configClasses.remove(identifier(configFactory));
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700130
Andrea Campanellae81e9412018-01-16 11:12:20 +0100131 // Removing the config factory only if this is the only ONOS instance or if it's the last
132 // instance active in a cluster. otherwise the other instances lose access to the config factory
133 // and can't use the associated net-cfgs.
134 if (clusterService.getNodes().size() == 1) {
135 // Note that we are deliberately not removing subject factory key bindings.
136 store.removeConfigFactory(configFactory);
137 }
ke han31dd5b42017-06-23 13:35:09 +0800138 }
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700139 }
140
141 @Override
142 public Set<ConfigFactory> getConfigFactories() {
143 return ImmutableSet.copyOf(factories.values());
144 }
145
146
147 @Override
148 @SuppressWarnings("unchecked")
149 public <S, C extends Config<S>> Set<ConfigFactory<S, C>> getConfigFactories(Class<S> subjectClass) {
150 ImmutableSet.Builder<ConfigFactory<S, C>> builder = ImmutableSet.builder();
151 factories.forEach((key, factory) -> {
152 if (factory.subjectFactory().subjectClass().equals(subjectClass)) {
153 builder.add(factory);
154 }
155 });
156 return builder.build();
157 }
158
159 @Override
160 public <S, C extends Config<S>> ConfigFactory<S, C> getConfigFactory(Class<C> configClass) {
161 checkNotNull(configClass, NULL_CCLASS_MSG);
162 return store.getConfigFactory(configClass);
163 }
164
165
166 @Override
167 public Set<Class> getSubjectClasses() {
Heedo Kang4a47a302016-02-29 17:40:23 +0900168 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700169 ImmutableSet.Builder<Class> builder = ImmutableSet.builder();
170 factories.forEach((k, v) -> builder.add(k.subjectClass));
171 return builder.build();
172 }
173
174 @Override
Thomas Vachuskaea5adc62015-10-07 11:52:30 -0700175 public SubjectFactory getSubjectFactory(String subjectClassKey) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900176 checkPermission(CONFIG_READ);
Thomas Vachuskaea5adc62015-10-07 11:52:30 -0700177 return subjectClasses.get(subjectClassKey);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700178 }
179
180 @Override
181 public SubjectFactory getSubjectFactory(Class subjectClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900182 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700183 return subjectClassKeys.get(subjectClass);
184 }
185
186 @Override
Thomas Vachuskaea5adc62015-10-07 11:52:30 -0700187 public Class<? extends Config> getConfigClass(String subjectClassKey, String configKey) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900188 checkPermission(CONFIG_READ);
Simon Hunt3da1a182016-02-08 16:42:54 -0800189 checkNotNull(subjectClassKey, NULL_SCKEY_MSG);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800190 checkNotNull(configKey, NULL_CKEY_MSG);
Thomas Vachuskaea5adc62015-10-07 11:52:30 -0700191 return configClasses.get(new ConfigIdentifier(subjectClassKey, configKey));
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700192 }
193
194 @Override
195 public <S> Set<S> getSubjects(Class<S> subjectClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900196 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700197 checkNotNull(subjectClass, NULL_SCLASS_MSG);
198 return store.getSubjects(subjectClass);
199 }
200
201 @Override
202 public <S, C extends Config<S>> Set<S> getSubjects(Class<S> subjectClass, Class<C> configClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900203 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700204 checkNotNull(subjectClass, NULL_SCLASS_MSG);
205 checkNotNull(configClass, NULL_CCLASS_MSG);
206 return store.getSubjects(subjectClass, configClass);
207 }
208
209 @Override
210 public <S> Set<Config<S>> getConfigs(S subject) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900211 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700212 checkNotNull(subject, NULL_SUBJECT_MSG);
213 Set<Class<? extends Config<S>>> configClasses = store.getConfigClasses(subject);
214 ImmutableSet.Builder<Config<S>> cfg = ImmutableSet.builder();
215 configClasses.forEach(cc -> cfg.add(store.getConfig(subject, cc)));
216 return cfg.build();
217 }
218
219 @Override
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800220 public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900221 checkPermission(CONFIG_READ);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700222 checkNotNull(subject, NULL_SUBJECT_MSG);
223 checkNotNull(configClass, NULL_CCLASS_MSG);
224 return store.getConfig(subject, configClass);
225 }
226
227
228 @Override
229 public <S, C extends Config<S>> C addConfig(S subject, Class<C> configClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900230 checkPermission(CONFIG_WRITE);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700231 checkNotNull(subject, NULL_SUBJECT_MSG);
232 checkNotNull(configClass, NULL_CCLASS_MSG);
233 return store.createConfig(subject, configClass);
234 }
235
236 @Override
Thomas Vachuska0a400ea2015-09-04 11:25:03 -0700237 public <S, C extends Config<S>> C applyConfig(S subject, Class<C> configClass, JsonNode json) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900238 checkPermission(CONFIG_WRITE);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700239 checkNotNull(subject, NULL_SUBJECT_MSG);
240 checkNotNull(configClass, NULL_CCLASS_MSG);
Simon Hunt3da1a182016-02-08 16:42:54 -0800241 checkNotNull(json, NULL_JSON_MSG);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700242 return store.applyConfig(subject, configClass, json);
243 }
244
245 @Override
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800246 @SuppressWarnings("unchecked")
247 public <S, C extends Config<S>> C applyConfig(String subjectClassKey, S subject,
248 String configKey, JsonNode json) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900249 checkPermission(CONFIG_WRITE);
Simon Hunt3da1a182016-02-08 16:42:54 -0800250 checkNotNull(subjectClassKey, NULL_SCKEY_MSG);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800251 checkNotNull(subject, NULL_SUBJECT_MSG);
252 checkNotNull(configKey, NULL_CKEY_MSG);
Simon Hunt3da1a182016-02-08 16:42:54 -0800253 checkNotNull(json, NULL_JSON_MSG);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800254 Class<? extends Config> configClass = configClasses.get(new ConfigIdentifier(subjectClassKey, configKey));
255 if (configClass != null) {
256 return store.applyConfig(subject, (Class<C>) configClass, json);
257 } else {
Andrea Campanelladcb5e932016-01-11 17:32:23 -0800258 log.info("Configuration \'{}\' queued for subject {}", configKey, subject);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800259 store.queueConfig(subject, configKey, json);
260 return null;
261 }
262 }
263
264 @Override
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700265 public <S, C extends Config<S>> void removeConfig(S subject, Class<C> configClass) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900266 checkPermission(CONFIG_WRITE);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700267 checkNotNull(subject, NULL_SUBJECT_MSG);
268 checkNotNull(configClass, NULL_CCLASS_MSG);
269 store.clearConfig(subject, configClass);
270 }
271
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800272 @Override
273 public <S> void removeConfig(String subjectClassKey, S subject, String configKey) {
Simon Hunt3da1a182016-02-08 16:42:54 -0800274 checkNotNull(subjectClassKey, NULL_SCKEY_MSG);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800275 checkNotNull(subject, NULL_SUBJECT_MSG);
Simon Hunt3da1a182016-02-08 16:42:54 -0800276 checkNotNull(configKey, NULL_CKEY_MSG);
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800277 Class<? extends Config> configClass = configClasses.get(new ConfigIdentifier(subjectClassKey, configKey));
278 if (configClass != null) {
279 store.clearConfig(subject, configClass);
280 } else {
281 store.clearQueuedConfig(subject, configKey);
Andrea Campanellae81e9412018-01-16 11:12:20 +0100282 }
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800283 }
284
Andrea Campanellae81e9412018-01-16 11:12:20 +0100285 @Override
286 public <S> void removeConfig(S subject) {
Deepa Vaddireddy0c49b602016-06-02 12:19:07 +0530287 checkPermission(CONFIG_WRITE);
288 store.clearConfig(subject);
Andrea Campanellae81e9412018-01-16 11:12:20 +0100289 }
Deepa Vaddireddy0c49b602016-06-02 12:19:07 +0530290
Andrea Campanellae81e9412018-01-16 11:12:20 +0100291 @Override
292 public <S> void removeConfig() {
293 checkPermission(CONFIG_WRITE);
294 store.clearConfig();
295 }
Deepa Vaddireddy0c49b602016-06-02 12:19:07 +0530296
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700297 // Auxiliary store delegate to receive notification about changes in
298 // the network configuration store state - by the store itself.
299 private class InternalStoreDelegate implements NetworkConfigStoreDelegate {
300 @Override
301 public void notify(NetworkConfigEvent event) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700302 post(event);
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700303 }
304 }
305
306
307 // Produces a key for uniquely tracking a config factory.
308 private static ConfigKey key(ConfigFactory factory) {
309 return new ConfigKey(factory.subjectFactory().subjectClass(), factory.configClass());
310 }
311
312 // Auxiliary key to track config factories.
Ray Milkeyae9faf12015-08-03 15:52:26 -0700313 protected static final class ConfigKey {
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700314 final Class subjectClass;
315 final Class configClass;
316
Ray Milkeyae9faf12015-08-03 15:52:26 -0700317 protected ConfigKey(Class subjectClass, Class configClass) {
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700318 this.subjectClass = subjectClass;
319 this.configClass = configClass;
320 }
321
322 @Override
323 public int hashCode() {
324 return Objects.hash(subjectClass, configClass);
325 }
326
327 @Override
328 public boolean equals(Object obj) {
329 if (this == obj) {
330 return true;
331 }
332 if (obj instanceof ConfigKey) {
333 final ConfigKey other = (ConfigKey) obj;
334 return Objects.equals(this.subjectClass, other.subjectClass)
335 && Objects.equals(this.configClass, other.configClass);
336 }
337 return false;
338 }
339 }
340
Jonathan Hart111b42b2015-07-14 13:28:05 -0700341 private static ConfigIdentifier identifier(ConfigFactory factory) {
Thomas Vachuskaea5adc62015-10-07 11:52:30 -0700342 return new ConfigIdentifier(factory.subjectFactory().subjectClassKey(), factory.configKey());
Jonathan Hart111b42b2015-07-14 13:28:05 -0700343 }
344
Thomas Vachuska4998caa2015-08-26 13:28:38 -0700345 static final class ConfigIdentifier {
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800346 final String subjectClassKey;
Jonathan Hart111b42b2015-07-14 13:28:05 -0700347 final String configKey;
348
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800349 protected ConfigIdentifier(String subjectClassKey, String configKey) {
350 this.subjectClassKey = subjectClassKey;
Jonathan Hart111b42b2015-07-14 13:28:05 -0700351 this.configKey = configKey;
352 }
353
354 @Override
355 public int hashCode() {
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800356 return Objects.hash(subjectClassKey, configKey);
Jonathan Hart111b42b2015-07-14 13:28:05 -0700357 }
358
359 @Override
360 public boolean equals(Object obj) {
361 if (this == obj) {
362 return true;
363 }
364 if (obj instanceof ConfigIdentifier) {
365 final ConfigIdentifier other = (ConfigIdentifier) obj;
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800366 return Objects.equals(this.subjectClassKey, other.subjectClassKey)
Jonathan Hart111b42b2015-07-14 13:28:05 -0700367 && Objects.equals(this.configKey, other.configKey);
368 }
369 return false;
370 }
371 }
Thomas Vachuska6f350ed2016-01-08 09:53:03 -0800372
Thomas Vachuska96d55b12015-05-11 08:52:03 -0700373}