e389b1dd330a9a6c196a383b8b9345ea07af84b7
[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         if (dataProvider != null) {
122             InstanceIdentifier<Endpoints> iid =
123                     InstanceIdentifier.builder(Endpoints.class).build();
124             WriteTransaction t = this.dataProvider.newWriteOnlyTransaction();
125             t.put(LogicalDatastoreType.OPERATIONAL,
126                     iid, new EndpointsBuilder().build());
127             CheckedFuture<Void, TransactionCommitFailedException> f = t.submit();
128             Futures.addCallback(f, new FutureCallback<Void>() {
129                 @Override
130                 public void onFailure(Throwable t) {
131                     LOG.error("Could not write endpoint base container", t);
132                 }
133
134                 @Override
135                 public void onSuccess(Void result) {
136
137                 }
138             });
139         }
140
141         // TODO Be alagalah - age out endpoint data and remove
142         // endpoint group/condition mappings with no conditions
143     }
144
145     @Override
146     public void close() throws Exception {
147         if (rpcRegistration != null) {
148             rpcRegistration.close();
149         }
150     }
151
152     /**
153      * Construct an endpoint with the appropriate augmentations from the
154      * endpoint input. Each concrete implementation can provides its specifics
155      * earlier.
156      *
157      * @param input
158      *            the input object
159      */
160     private EndpointBuilder buildEndpoint(RegisterEndpointInput input) {
161         EndpointBuilder eb = new EndpointBuilder(input);
162         for (Entry<String, EpRendererAugmentation> entry : registeredRenderers
163                 .entrySet()) {
164             try {
165                 Map.Entry<Class<? extends Augmentation<Endpoint>>, Augmentation<Endpoint>> augmentationEntry =
166                         entry.getValue().buildEndpointAugmentation(input);
167                 if (augmentationEntry != null) {
168                     eb.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
169                 }
170             } catch (Exception e) {
171                 LOG.warn("Endpoint Augmentation error while processing "
172                         + entry.getKey() + ". Reason: ", e);
173             }
174         }
175         return eb;
176     }
177
178     /**
179      * Construct an L3 endpoint with the appropriate augmentations from the
180      * endpoint input. Each concrete implementation can provides its specifics
181      * earlier.
182      *
183      * @param input
184      *            the input object
185      */
186     private EndpointL3Builder buildEndpointL3(RegisterEndpointInput input) {
187         EndpointL3Builder eb = new EndpointL3Builder(input);
188         for (Entry<String, EpRendererAugmentation> entry : registeredRenderers
189                 .entrySet()) {
190             try {
191                 Map.Entry<Class<? extends Augmentation<EndpointL3>>, Augmentation<EndpointL3>> augmentationEntry =
192                         entry.getValue().buildEndpointL3Augmentation(input);
193                 if (augmentationEntry != null) {
194                     eb.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
195                 }
196             } catch (Exception e) {
197                 LOG.warn("L3 endpoint Augmentation error while processing "
198                         + entry.getKey() + ". Reason: ", e);
199             }
200         }
201         return eb;
202     }
203
204     /**
205      * Construct an L3 endpoint with the appropriate augmentations from the
206      * endpoint input. Each concrete implementation can provides its specifics
207      * earlier.
208      *
209      * @param input
210      *            the input object
211      */
212     private EndpointL3PrefixBuilder buildL3PrefixEndpoint(RegisterL3PrefixEndpointInput input) {
213         EndpointL3PrefixBuilder eb = new EndpointL3PrefixBuilder(input);
214         for (Entry<String, EpRendererAugmentation> entry : registeredRenderers
215                 .entrySet()) {
216             try {
217                 Map.Entry<Class<? extends Augmentation<EndpointL3Prefix>>, Augmentation<EndpointL3Prefix>> augmentationEntry =
218                         entry.getValue().buildL3PrefixEndpointAugmentation(input);
219                 if (augmentationEntry != null) {
220                     eb.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
221                 }
222             } catch (Exception e) {
223                 LOG.warn("L3 endpoint Augmentation error while processing "
224                         + entry.getKey() + ". Reason: ", e);
225             }
226         }
227         return eb;
228     }
229
230     @Override
231     public Future<RpcResult<Void>>
232             registerEndpoint(RegisterEndpointInput input) {
233         long timestamp = System.currentTimeMillis();
234
235         // TODO: Replicate RPC feedback implemented in L3Prefix register for
236         // unmet requirements.
237         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
238
239         if (input.getL2Context() != null &&
240                 input.getMacAddress() != null) {
241             Endpoint ep = buildEndpoint(input)
242                     .setTimestamp(timestamp)
243                     .build();
244
245             EndpointKey key =
246                     new EndpointKey(ep.getL2Context(), ep.getMacAddress());
247             InstanceIdentifier<Endpoint> iid =
248                     InstanceIdentifier.builder(Endpoints.class)
249                             .child(Endpoint.class, key)
250                             .build();
251             t.put(LogicalDatastoreType.OPERATIONAL, iid, ep, true);
252         }
253         if (input.getL3Address() != null) {
254             for (L3Address l3addr : input.getL3Address()) {
255                 EndpointL3Key key3 = new EndpointL3Key(l3addr.getIpAddress(),
256                         l3addr.getL3Context());
257                 EndpointL3 ep3 = buildEndpointL3(input)
258                         .setIpAddress(key3.getIpAddress())
259                         .setL3Context(key3.getL3Context())
260                         .setTimestamp(timestamp)
261                         .build();
262                 InstanceIdentifier<EndpointL3> iid_l3 =
263                         InstanceIdentifier.builder(Endpoints.class)
264                                 .child(EndpointL3.class, key3)
265                                 .build();
266                 t.put(LogicalDatastoreType.OPERATIONAL, iid_l3, ep3, true);
267             }
268         }
269         ListenableFuture<Void> r = t.submit();
270         return Futures.transform(r, futureTrans);
271     }
272
273     @Override
274     public Future<RpcResult<Void>> registerL3PrefixEndpoint(RegisterL3PrefixEndpointInput input) {
275
276         if (input.getL3Context() == null) {
277             return Futures.immediateFuture(RpcResultBuilder.<Void> failed()
278                     .withError(ErrorType.RPC, "L3 Prefix Endpoint must have L3Context.").build());
279         }
280         if (input.getIpPrefix() == null) {
281             return Futures.immediateFuture(RpcResultBuilder.<Void> failed()
282                     .withError(ErrorType.RPC, "L3 Prefix Endpoint must have ip-prefix.").build());
283         }
284
285         if (input.getTenant() == null) {
286             return Futures.immediateFuture(RpcResultBuilder.<Void> failed()
287                     .withError(ErrorType.RPC, "L3 Prefix Endpoint must have tenant.").build());
288         }
289
290         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
291
292         long timestamp = System.currentTimeMillis();
293
294         // TODO: Convert IPPrefix into it's IPv4/IPv6 canonical form.
295         // See org.apache.commons.net.util.SubnetUtils.SubnetInfo
296
297         EndpointL3PrefixKey epL3PrefixKey = new EndpointL3PrefixKey(input.getIpPrefix(), input.getL3Context());
298
299         EndpointL3Prefix epL3Prefix = buildL3PrefixEndpoint(input).setTimestamp(timestamp).build();
300         InstanceIdentifier<EndpointL3Prefix> iid_l3prefix =
301                 InstanceIdentifier.builder(Endpoints.class)
302                         .child(EndpointL3Prefix.class, epL3PrefixKey)
303                         .build();
304         t.put(LogicalDatastoreType.OPERATIONAL, iid_l3prefix, epL3Prefix);
305
306         ListenableFuture<Void> r = t.submit();
307         return Futures.transform(r, futureTrans);
308     }
309
310     @Override
311     public Future<RpcResult<Void>>
312             unregisterEndpoint(UnregisterEndpointInput input) {
313         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
314         if (input.getL2() != null) {
315             for (L2 l2a : input.getL2()) {
316                 EndpointKey key =
317                         new EndpointKey(l2a.getL2Context(),
318                                 l2a.getMacAddress());
319                 InstanceIdentifier<Endpoint> iid =
320                         InstanceIdentifier.builder(Endpoints.class)
321                                 .child(Endpoint.class, key).build();
322                 t.delete(LogicalDatastoreType.OPERATIONAL, iid);
323             }
324         }
325         if (input.getL3() != null) {
326             for (L3 l3addr : input.getL3()) {
327                 EndpointL3Key key3 =
328                         new EndpointL3Key(l3addr.getIpAddress(),
329                                 l3addr.getL3Context());
330                 InstanceIdentifier<EndpointL3> iid_l3 =
331                         InstanceIdentifier.builder(Endpoints.class)
332                                 .child(EndpointL3.class, key3)
333                                 .build();
334                 t.delete(LogicalDatastoreType.OPERATIONAL, iid_l3);
335             }
336         }
337         // TODO: Implement L3Prefix
338
339         ListenableFuture<Void> r = t.submit();
340         return Futures.transform(r, futureTrans);
341     }
342
343     @Override
344     public Future<RpcResult<Void>>
345             setEndpointGroupConditions(SetEndpointGroupConditionsInput input) {
346         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
347
348         ConditionMappingKey key =
349                 new ConditionMappingKey(input.getEndpointGroup());
350
351         for (EndpointGroupCondition condition : input.getEndpointGroupCondition()) {
352             EndpointGroupConditionKey ckey =
353                     new EndpointGroupConditionKey(condition.getCondition());
354             InstanceIdentifier<EndpointGroupCondition> iid =
355                     InstanceIdentifier.builder(Endpoints.class)
356                             .child(ConditionMapping.class, key)
357                             .child(EndpointGroupCondition.class, ckey)
358                             .build();
359             t.put(LogicalDatastoreType.OPERATIONAL, iid, condition);
360         }
361
362         ListenableFuture<Void> r = t.submit();
363         return Futures.transform(r, futureTrans);
364     }
365
366     @Override
367     public Future<RpcResult<Void>>
368             unsetEndpointGroupConditions(UnsetEndpointGroupConditionsInput input) {
369         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
370
371         ConditionMappingKey key =
372                 new ConditionMappingKey(input.getEndpointGroup());
373
374         for (EndpointGroupCondition condition : input.getEndpointGroupCondition()) {
375             EndpointGroupConditionKey ckey =
376                     new EndpointGroupConditionKey(condition.getCondition());
377             InstanceIdentifier<EndpointGroupCondition> iid =
378                     InstanceIdentifier.builder(Endpoints.class)
379                             .child(ConditionMapping.class, key)
380                             .child(EndpointGroupCondition.class, ckey)
381                             .build();
382
383             t.delete(LogicalDatastoreType.OPERATIONAL, iid);
384         }
385
386         ListenableFuture<Void> r = t.submit();
387         return Futures.transform(r, futureTrans);
388     }
389
390     Function<Void, RpcResult<Void>> futureTrans =
391             new Function<Void, RpcResult<Void>>() {
392                 @Override
393                 public RpcResult<Void> apply(Void input) {
394                     return RpcResultBuilder.<Void> success().build();
395                 }
396             };
397 }