Rework IOVisor model and validate IovisorModuleInstance on Endpoint created events
[groupbasedpolicy.git] / groupbasedpolicy / src / main / java / org / opendaylight / groupbasedpolicy / endpoint / EndpointRpcRegistry.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.groupbasedpolicy.endpoint;
10
11 import java.util.Map;
12 import java.util.Map.Entry;
13 import java.util.concurrent.ConcurrentHashMap;
14 import java.util.concurrent.ConcurrentMap;
15 import java.util.concurrent.Future;
16
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
21 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
22 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointsBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterL3PrefixEndpointInput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.SetEndpointGroupConditionsInput;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnsetEndpointGroupConditionsInput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.ConditionMapping;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.ConditionMappingKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Builder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3PrefixBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3PrefixKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.has.endpoint.group.conditions.EndpointGroupCondition;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.has.endpoint.group.conditions.EndpointGroupConditionKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3;
47 import org.opendaylight.yangtools.yang.binding.Augmentation;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
50 import org.opendaylight.yangtools.yang.common.RpcResult;
51 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 import com.google.common.base.Function;
56 import com.google.common.util.concurrent.CheckedFuture;
57 import com.google.common.util.concurrent.FutureCallback;
58 import com.google.common.util.concurrent.Futures;
59 import com.google.common.util.concurrent.ListenableFuture;
60
61 /**
62  * Endpoint registry provides a scalable store for accessing and updating
63  * information about endpoints.
64  */
65 public class EndpointRpcRegistry implements EndpointService, AutoCloseable {
66     private static final Logger LOG =
67             LoggerFactory.getLogger(EndpointRpcRegistry.class);
68
69     private final DataBroker dataProvider;
70     private final RpcProviderRegistry rpcRegistry;
71
72     private final BindingAwareBroker.RpcRegistration<EndpointService> rpcRegistration;
73
74     final static ConcurrentMap<String, EpRendererAugmentation> registeredRenderers = new ConcurrentHashMap<String, EpRendererAugmentation>();
75
76     /**
77      * This method registers a renderer for endpoint RPC API. This method
78      * ensures single RPC registration for all renderers since a single RPC
79      * registration is only allowed.
80      *
81      * @param epRendererAugmentation
82      *            - specific implementation RPC augmentation, if any. Otherwise
83      *            NULL
84      */
85     public static void register(EpRendererAugmentation epRendererAugmentation) {
86         if (epRendererAugmentation != null) {
87             registeredRenderers.putIfAbsent(epRendererAugmentation.getClass().getName(), epRendererAugmentation);
88             LOG.info("Registered {}", epRendererAugmentation.getClass().getName());
89         }
90     }
91
92     /**
93      *
94      * @param regImp the endpoint augmentation
95      * @throws Exception
96      */
97     public static void unregister(EpRendererAugmentation regImp) throws Exception {
98         if (regImp == null || !registeredRenderers.containsKey(regImp.getClass().getName())) {
99             return;
100         }
101         registeredRenderers.remove(regImp.getClass().getName());
102         LOG.info("Unregistered {}", regImp.getClass().getName());
103     }
104
105     /**
106      * Constructor
107      *
108      * @param dataProvider the {@link DataBroker}
109      * @param rpcRegistry  the {@link RpcProviderRegistry}
110      */
111     public EndpointRpcRegistry(DataBroker dataProvider, RpcProviderRegistry rpcRegistry) {
112         this.dataProvider = dataProvider;
113         this.rpcRegistry = rpcRegistry;
114         if (this.rpcRegistry != null) {
115             rpcRegistration =
116                     this.rpcRegistry.addRpcImplementation(EndpointService.class, this);
117             LOG.debug("Added RPC Implementation Correctly");
118         } else {
119             rpcRegistration = null;
120         }
121
122         if (dataProvider != null) {
123             InstanceIdentifier<Endpoints> iid =
124                     InstanceIdentifier.builder(Endpoints.class).build();
125             WriteTransaction t = this.dataProvider.newWriteOnlyTransaction();
126             t.put(LogicalDatastoreType.OPERATIONAL,
127                     iid, new EndpointsBuilder().build());
128             CheckedFuture<Void, TransactionCommitFailedException> f = t.submit();
129             Futures.addCallback(f, new FutureCallback<Void>() {
130                 @Override
131                 public void onFailure(Throwable t) {
132                     LOG.error("Could not write endpoint base container", t);
133                 }
134
135                 @Override
136                 public void onSuccess(Void result) {
137
138                 }
139             });
140         }
141
142         // TODO Be alagalah - age out endpoint data and remove
143         // endpoint group/condition mappings with no conditions
144     }
145
146     @Override
147     public void close() throws Exception {
148         if (rpcRegistration != null) {
149             rpcRegistration.close();
150         }
151     }
152
153     /**
154      * Construct an endpoint with the appropriate augmentations from the
155      * endpoint input. Each concrete implementation can provides its specifics
156      * earlier.
157      *
158      * @param input
159      *            the input object
160      */
161     private EndpointBuilder buildEndpoint(RegisterEndpointInput input) {
162         EndpointBuilder eb = new EndpointBuilder(input);
163         for (Entry<String, EpRendererAugmentation> entry : registeredRenderers
164                 .entrySet()) {
165             try {
166                 Map.Entry<Class<? extends Augmentation<Endpoint>>, Augmentation<Endpoint>> augmentationEntry =
167                         entry.getValue().buildEndpointAugmentation(input);
168                 if (augmentationEntry != null) {
169                     eb.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
170                 }
171             } catch (Exception e) {
172                 LOG.warn("Endpoint Augmentation error while processing "
173                         + entry.getKey() + ". Reason: ", e);
174             }
175         }
176         return eb;
177     }
178
179     /**
180      * Construct an L3 endpoint with the appropriate augmentations from the
181      * endpoint input. Each concrete implementation can provides its specifics
182      * earlier.
183      *
184      * @param input
185      *            the input object
186      */
187     private EndpointL3Builder buildEndpointL3(RegisterEndpointInput input) {
188         EndpointL3Builder eb = new EndpointL3Builder(input);
189         for (Entry<String, EpRendererAugmentation> entry : registeredRenderers
190                 .entrySet()) {
191             try {
192                 Map.Entry<Class<? extends Augmentation<EndpointL3>>, Augmentation<EndpointL3>> augmentationEntry =
193                         entry.getValue().buildEndpointL3Augmentation(input);
194                 if (augmentationEntry != null) {
195                     eb.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
196                 }
197             } catch (Exception e) {
198                 LOG.warn("L3 endpoint Augmentation error while processing "
199                         + entry.getKey() + ". Reason: ", e);
200             }
201         }
202         return eb;
203     }
204
205     /**
206      * Construct an L3 endpoint with the appropriate augmentations from the
207      * endpoint input. Each concrete implementation can provides its specifics
208      * earlier.
209      *
210      * @param input
211      *            the input object
212      */
213     private EndpointL3PrefixBuilder buildL3PrefixEndpoint(RegisterL3PrefixEndpointInput input) {
214         EndpointL3PrefixBuilder eb = new EndpointL3PrefixBuilder(input);
215         for (Entry<String, EpRendererAugmentation> entry : registeredRenderers
216                 .entrySet()) {
217             try {
218                 Map.Entry<Class<? extends Augmentation<EndpointL3Prefix>>, Augmentation<EndpointL3Prefix>> augmentationEntry =
219                         entry.getValue().buildL3PrefixEndpointAugmentation(input);
220                 if (augmentationEntry != null) {
221                     eb.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
222                 }
223             } catch (Exception e) {
224                 LOG.warn("L3 endpoint Augmentation error while processing "
225                         + entry.getKey() + ". Reason: ", e);
226             }
227         }
228         return eb;
229     }
230
231     @Override
232     public Future<RpcResult<Void>>
233             registerEndpoint(RegisterEndpointInput input) {
234         long timestamp = System.currentTimeMillis();
235
236         // TODO: Replicate RPC feedback implemented in L3Prefix register for
237         // unmet requirements.
238         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
239
240         if (input.getL2Context() != null &&
241                 input.getMacAddress() != null) {
242             Endpoint ep = buildEndpoint(input)
243                     .setTimestamp(timestamp)
244                     .build();
245
246             EndpointKey key =
247                     new EndpointKey(ep.getL2Context(), ep.getMacAddress());
248             InstanceIdentifier<Endpoint> iid =
249                     InstanceIdentifier.builder(Endpoints.class)
250                             .child(Endpoint.class, key)
251                             .build();
252             t.put(LogicalDatastoreType.OPERATIONAL, iid, ep, true);
253         }
254         if (input.getL3Address() != null) {
255             for (L3Address l3addr : input.getL3Address()) {
256                 EndpointL3Key key3 = new EndpointL3Key(l3addr.getIpAddress(),
257                         l3addr.getL3Context());
258                 EndpointL3 ep3 = buildEndpointL3(input)
259                         .setIpAddress(key3.getIpAddress())
260                         .setL3Context(key3.getL3Context())
261                         .setTimestamp(timestamp)
262                         .build();
263                 InstanceIdentifier<EndpointL3> iid_l3 =
264                         InstanceIdentifier.builder(Endpoints.class)
265                                 .child(EndpointL3.class, key3)
266                                 .build();
267                 t.put(LogicalDatastoreType.OPERATIONAL, iid_l3, ep3, true);
268             }
269         }
270         ListenableFuture<Void> r = t.submit();
271         return Futures.transform(r, futureTrans);
272     }
273
274     @Override
275     public Future<RpcResult<Void>> registerL3PrefixEndpoint(RegisterL3PrefixEndpointInput input) {
276
277         if (input.getL3Context() == null) {
278             return Futures.immediateFuture(RpcResultBuilder.<Void> failed()
279                     .withError(ErrorType.RPC, "L3 Prefix Endpoint must have L3Context.").build());
280         }
281         if (input.getIpPrefix() == null) {
282             return Futures.immediateFuture(RpcResultBuilder.<Void> failed()
283                     .withError(ErrorType.RPC, "L3 Prefix Endpoint must have ip-prefix.").build());
284         }
285
286         if (input.getTenant() == null) {
287             return Futures.immediateFuture(RpcResultBuilder.<Void> failed()
288                     .withError(ErrorType.RPC, "L3 Prefix Endpoint must have tenant.").build());
289         }
290
291         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
292
293         long timestamp = System.currentTimeMillis();
294
295         // TODO: Convert IPPrefix into it's IPv4/IPv6 canonical form.
296         // See org.apache.commons.net.util.SubnetUtils.SubnetInfo
297
298         EndpointL3PrefixKey epL3PrefixKey = new EndpointL3PrefixKey(input.getIpPrefix(), input.getL3Context());
299
300         EndpointL3Prefix epL3Prefix = buildL3PrefixEndpoint(input).setTimestamp(timestamp).build();
301         InstanceIdentifier<EndpointL3Prefix> iid_l3prefix =
302                 InstanceIdentifier.builder(Endpoints.class)
303                         .child(EndpointL3Prefix.class, epL3PrefixKey)
304                         .build();
305         t.put(LogicalDatastoreType.OPERATIONAL, iid_l3prefix, epL3Prefix);
306
307         ListenableFuture<Void> r = t.submit();
308         return Futures.transform(r, futureTrans);
309     }
310
311     @Override
312     public Future<RpcResult<Void>>
313             unregisterEndpoint(UnregisterEndpointInput input) {
314         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
315         if (input.getL2() != null) {
316             for (L2 l2a : input.getL2()) {
317                 EndpointKey key =
318                         new EndpointKey(l2a.getL2Context(),
319                                 l2a.getMacAddress());
320                 InstanceIdentifier<Endpoint> iid =
321                         InstanceIdentifier.builder(Endpoints.class)
322                                 .child(Endpoint.class, key).build();
323                 t.delete(LogicalDatastoreType.OPERATIONAL, iid);
324             }
325         }
326         if (input.getL3() != null) {
327             for (L3 l3addr : input.getL3()) {
328                 EndpointL3Key key3 =
329                         new EndpointL3Key(l3addr.getIpAddress(),
330                                 l3addr.getL3Context());
331                 InstanceIdentifier<EndpointL3> iid_l3 =
332                         InstanceIdentifier.builder(Endpoints.class)
333                                 .child(EndpointL3.class, key3)
334                                 .build();
335                 t.delete(LogicalDatastoreType.OPERATIONAL, iid_l3);
336             }
337         }
338         // TODO: Implement L3Prefix
339
340         ListenableFuture<Void> r = t.submit();
341         return Futures.transform(r, futureTrans);
342     }
343
344     @Override
345     public Future<RpcResult<Void>>
346             setEndpointGroupConditions(SetEndpointGroupConditionsInput input) {
347         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
348
349         ConditionMappingKey key =
350                 new ConditionMappingKey(input.getEndpointGroup());
351
352         for (EndpointGroupCondition condition : input.getEndpointGroupCondition()) {
353             EndpointGroupConditionKey ckey =
354                     new EndpointGroupConditionKey(condition.getCondition());
355             InstanceIdentifier<EndpointGroupCondition> iid =
356                     InstanceIdentifier.builder(Endpoints.class)
357                             .child(ConditionMapping.class, key)
358                             .child(EndpointGroupCondition.class, ckey)
359                             .build();
360             t.put(LogicalDatastoreType.OPERATIONAL, iid, condition);
361         }
362
363         ListenableFuture<Void> r = t.submit();
364         return Futures.transform(r, futureTrans);
365     }
366
367     @Override
368     public Future<RpcResult<Void>>
369             unsetEndpointGroupConditions(UnsetEndpointGroupConditionsInput input) {
370         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
371
372         ConditionMappingKey key =
373                 new ConditionMappingKey(input.getEndpointGroup());
374
375         for (EndpointGroupCondition condition : input.getEndpointGroupCondition()) {
376             EndpointGroupConditionKey ckey =
377                     new EndpointGroupConditionKey(condition.getCondition());
378             InstanceIdentifier<EndpointGroupCondition> iid =
379                     InstanceIdentifier.builder(Endpoints.class)
380                             .child(ConditionMapping.class, key)
381                             .child(EndpointGroupCondition.class, ckey)
382                             .build();
383
384             t.delete(LogicalDatastoreType.OPERATIONAL, iid);
385         }
386
387         ListenableFuture<Void> r = t.submit();
388         return Futures.transform(r, futureTrans);
389     }
390
391     Function<Void, RpcResult<Void>> futureTrans =
392             new Function<Void, RpcResult<Void>>() {
393                 @Override
394                 public RpcResult<Void> apply(Void input) {
395                     return RpcResultBuilder.<Void> success().build();
396                 }
397             };
398 }