c2e4662505d95a29e5b4d0cc16e46d594080601f
[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.groupbasedpolicy.api.EpRendererAugmentation;
22 import org.opendaylight.groupbasedpolicy.api.EpRendererAugmentationRegistry;
23 import org.opendaylight.groupbasedpolicy.util.IidFactory;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointsBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterL3PrefixEndpointInput;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.SetEndpointGroupConditionsInput;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnsetEndpointGroupConditionsInput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.ConditionMapping;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.ConditionMappingKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Builder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Key;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3PrefixBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3PrefixKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.has.endpoint.group.conditions.EndpointGroupCondition;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.has.endpoint.group.conditions.EndpointGroupConditionKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3Prefix;
49 import org.opendaylight.yangtools.yang.binding.Augmentation;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
52 import org.opendaylight.yangtools.yang.common.RpcResult;
53 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 import com.google.common.base.Function;
58 import com.google.common.util.concurrent.CheckedFuture;
59 import com.google.common.util.concurrent.FutureCallback;
60 import com.google.common.util.concurrent.Futures;
61 import com.google.common.util.concurrent.ListenableFuture;
62
63 /**
64  * Endpoint registry provides a scalable store for accessing and updating
65  * information about endpoints.
66  */
67 public class EndpointRpcRegistry implements EndpointService, EpRendererAugmentationRegistry, AutoCloseable {
68
69     private static final Logger LOG = LoggerFactory.getLogger(EndpointRpcRegistry.class);
70
71     private final DataBroker dataProvider;
72
73     final static ConcurrentMap<String, EpRendererAugmentation> registeredRenderers =
74             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     @Override
86     public void register(EpRendererAugmentation epRendererAugmentation) {
87         if (epRendererAugmentation != null) {
88             registeredRenderers.putIfAbsent(epRendererAugmentation.getClass().getName(), epRendererAugmentation);
89             LOG.info("Registered {}", epRendererAugmentation.getClass().getName());
90         }
91     }
92
93     /**
94      * @param regImp the endpoint augmentation
95      */
96     @Override
97     public void unregister(EpRendererAugmentation regImp) {
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      */
110     public EndpointRpcRegistry(DataBroker dataProvider) {
111         this.dataProvider = dataProvider;
112
113         if (dataProvider != null) {
114             InstanceIdentifier<Endpoints> iid = InstanceIdentifier.builder(Endpoints.class).build();
115             WriteTransaction t = this.dataProvider.newWriteOnlyTransaction();
116             t.put(LogicalDatastoreType.OPERATIONAL, iid, new EndpointsBuilder().build());
117             CheckedFuture<Void, TransactionCommitFailedException> f = t.submit();
118             Futures.addCallback(f, new FutureCallback<Void>() {
119
120                 @Override
121                 public void onFailure(Throwable t) {
122                     LOG.error("Could not write endpoint base container", t);
123                 }
124
125                 @Override
126                 public void onSuccess(Void result) {
127
128                 }
129             });
130         }
131
132         // TODO Be alagalah - age out endpoint data and remove
133         // endpoint group/condition mappings with no conditions
134     }
135
136     @Override
137     public void close() {
138     }
139
140     /**
141      * Construct an endpoint with the appropriate augmentations from the
142      * endpoint input. Each concrete implementation can provides its specifics
143      * earlier.
144      *
145      * @param input
146      *        the input object
147      */
148     private EndpointBuilder buildEndpoint(RegisterEndpointInput input) {
149         EndpointBuilder eb = new EndpointBuilder(input);
150         for (Entry<String, EpRendererAugmentation> entry : registeredRenderers.entrySet()) {
151             try {
152                 Map.Entry<Class<? extends Augmentation<Endpoint>>, Augmentation<Endpoint>> augmentationEntry =
153                         entry.getValue().buildEndpointAugmentation(input);
154                 if (augmentationEntry != null) {
155                     eb.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
156                 }
157             } catch (Exception e) {
158                 LOG.warn("Endpoint Augmentation error while processing " + entry.getKey() + ". Reason: ", e);
159             }
160         }
161         return eb;
162     }
163
164     /**
165      * Construct an L3 endpoint with the appropriate augmentations from the
166      * endpoint input. Each concrete implementation can provides its specifics
167      * earlier.
168      *
169      * @param input
170      *        the input object
171      */
172     private EndpointL3Builder buildEndpointL3(RegisterEndpointInput input) {
173         EndpointL3Builder eb = new EndpointL3Builder(input);
174         for (Entry<String, EpRendererAugmentation> entry : registeredRenderers.entrySet()) {
175             try {
176                 Map.Entry<Class<? extends Augmentation<EndpointL3>>, Augmentation<EndpointL3>> augmentationEntry =
177                         entry.getValue().buildEndpointL3Augmentation(input);
178                 if (augmentationEntry != null) {
179                     eb.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
180                 }
181             } catch (Exception e) {
182                 LOG.warn("L3 endpoint Augmentation error while processing " + entry.getKey() + ". Reason: ", e);
183             }
184         }
185         return eb;
186     }
187
188     /**
189      * Construct an L3 endpoint with the appropriate augmentations from the
190      * endpoint input. Each concrete implementation can provides its specifics
191      * earlier.
192      *
193      * @param input
194      *        the input object
195      */
196     private EndpointL3PrefixBuilder buildL3PrefixEndpoint(RegisterL3PrefixEndpointInput input) {
197         EndpointL3PrefixBuilder eb = new EndpointL3PrefixBuilder(input);
198         for (Entry<String, EpRendererAugmentation> entry : registeredRenderers.entrySet()) {
199             try {
200                 Map.Entry<Class<? extends Augmentation<EndpointL3Prefix>>, Augmentation<EndpointL3Prefix>> augmentationEntry =
201                         entry.getValue().buildL3PrefixEndpointAugmentation(input);
202                 if (augmentationEntry != null) {
203                     eb.addAugmentation(augmentationEntry.getKey(), augmentationEntry.getValue());
204                 }
205             } catch (Exception e) {
206                 LOG.warn("L3 endpoint Augmentation error while processing " + entry.getKey() + ". Reason: ", e);
207             }
208         }
209         return eb;
210     }
211
212     @Override
213     public Future<RpcResult<Void>> registerEndpoint(RegisterEndpointInput input) {
214         long timestamp = System.currentTimeMillis();
215
216         // TODO: Replicate RPC feedback implemented in L3Prefix register for
217         // unmet requirements.
218         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
219
220         if (input.getL2Context() != null && input.getMacAddress() != null) {
221             Endpoint ep = buildEndpoint(input).setTimestamp(timestamp).build();
222
223             EndpointKey key = new EndpointKey(ep.getL2Context(), ep.getMacAddress());
224             t.put(LogicalDatastoreType.OPERATIONAL, IidFactory.endpointIid(key), ep, true);
225         }
226         if (input.getL3Address() != null) {
227             for (L3Address l3addr : input.getL3Address()) {
228                 EndpointL3Key key3 = new EndpointL3Key(l3addr.getIpAddress(), l3addr.getL3Context());
229                 EndpointL3 ep3 = buildEndpointL3(input).setIpAddress(key3.getIpAddress())
230                     .setL3Context(key3.getL3Context())
231                     .setTimestamp(timestamp)
232                     .build();
233                 t.put(LogicalDatastoreType.OPERATIONAL, IidFactory.l3EndpointIid(key3), ep3, true);
234             }
235         }
236         ListenableFuture<Void> r = t.submit();
237         return Futures.transform(r, futureTrans);
238     }
239
240     @Override
241     public Future<RpcResult<Void>> registerL3PrefixEndpoint(RegisterL3PrefixEndpointInput input) {
242
243         if (input.getL3Context() == null) {
244             return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
245                 .withError(ErrorType.RPC, "L3 Prefix Endpoint must have L3Context.")
246                 .build());
247         }
248         if (input.getIpPrefix() == null) {
249             return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
250                 .withError(ErrorType.RPC, "L3 Prefix Endpoint must have ip-prefix.")
251                 .build());
252         }
253
254         if (input.getTenant() == null) {
255             return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
256                 .withError(ErrorType.RPC, "L3 Prefix Endpoint must have tenant.")
257                 .build());
258         }
259
260         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
261
262         long timestamp = System.currentTimeMillis();
263
264         // TODO: Convert IPPrefix into it's IPv4/IPv6 canonical form.
265         // See org.apache.commons.net.util.SubnetUtils.SubnetInfo
266
267         EndpointL3PrefixKey epL3PrefixKey = new EndpointL3PrefixKey(input.getIpPrefix(), input.getL3Context());
268
269         EndpointL3Prefix epL3Prefix = buildL3PrefixEndpoint(input).setTimestamp(timestamp).build();
270         InstanceIdentifier<EndpointL3Prefix> iid_l3prefix =
271                 InstanceIdentifier.builder(Endpoints.class).child(EndpointL3Prefix.class, epL3PrefixKey).build();
272         t.put(LogicalDatastoreType.OPERATIONAL, iid_l3prefix, epL3Prefix);
273
274         ListenableFuture<Void> r = t.submit();
275         return Futures.transform(r, futureTrans);
276     }
277
278     @Override
279     public Future<RpcResult<Void>> unregisterEndpoint(UnregisterEndpointInput input) {
280         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
281         if (input.getL2() != null) {
282             for (L2 l2a : input.getL2()) {
283                 EndpointKey key = new EndpointKey(l2a.getL2Context(), l2a.getMacAddress());
284                 InstanceIdentifier<Endpoint> iid =
285                         InstanceIdentifier.builder(Endpoints.class).child(Endpoint.class, key).build();
286                 t.delete(LogicalDatastoreType.OPERATIONAL, iid);
287             }
288         }
289         if (input.getL3() != null) {
290             for (L3 l3addr : input.getL3()) {
291                 EndpointL3Key key3 = new EndpointL3Key(l3addr.getIpAddress(), l3addr.getL3Context());
292                 InstanceIdentifier<EndpointL3> iid_l3 =
293                         InstanceIdentifier.builder(Endpoints.class).child(EndpointL3.class, key3).build();
294                 t.delete(LogicalDatastoreType.OPERATIONAL, iid_l3);
295             }
296         }
297         if (input.getL3Prefix() != null) {
298             for (L3Prefix l3prefix : input.getL3Prefix()) {
299                 EndpointL3PrefixKey key = new EndpointL3PrefixKey(l3prefix.getIpPrefix(), l3prefix.getL3Context());
300                 InstanceIdentifier<EndpointL3Prefix> iidL3Prefix =
301                         InstanceIdentifier.builder(Endpoints.class).child(EndpointL3Prefix.class, key).build();
302                 t.delete(LogicalDatastoreType.OPERATIONAL, iidL3Prefix);
303             }
304         }
305
306         ListenableFuture<Void> r = t.submit();
307         return Futures.transform(r, futureTrans);
308     }
309
310     @Override
311     public Future<RpcResult<Void>> setEndpointGroupConditions(SetEndpointGroupConditionsInput input) {
312         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
313
314         ConditionMappingKey key = new ConditionMappingKey(input.getEndpointGroup());
315
316         for (EndpointGroupCondition condition : input.getEndpointGroupCondition()) {
317             EndpointGroupConditionKey ckey = new EndpointGroupConditionKey(condition.getCondition());
318             InstanceIdentifier<EndpointGroupCondition> iid = InstanceIdentifier.builder(Endpoints.class)
319                 .child(ConditionMapping.class, key)
320                 .child(EndpointGroupCondition.class, ckey)
321                 .build();
322             t.put(LogicalDatastoreType.OPERATIONAL, iid, condition);
323         }
324
325         ListenableFuture<Void> r = t.submit();
326         return Futures.transform(r, futureTrans);
327     }
328
329     @Override
330     public Future<RpcResult<Void>> unsetEndpointGroupConditions(UnsetEndpointGroupConditionsInput input) {
331         WriteTransaction t = dataProvider.newWriteOnlyTransaction();
332
333         ConditionMappingKey key = new ConditionMappingKey(input.getEndpointGroup());
334
335         for (EndpointGroupCondition condition : input.getEndpointGroupCondition()) {
336             EndpointGroupConditionKey ckey = new EndpointGroupConditionKey(condition.getCondition());
337             InstanceIdentifier<EndpointGroupCondition> iid = InstanceIdentifier.builder(Endpoints.class)
338                 .child(ConditionMapping.class, key)
339                 .child(EndpointGroupCondition.class, ckey)
340                 .build();
341
342             t.delete(LogicalDatastoreType.OPERATIONAL, iid);
343         }
344
345         ListenableFuture<Void> r = t.submit();
346         return Futures.transform(r, futureTrans);
347     }
348
349     Function<Void, RpcResult<Void>> futureTrans = new Function<Void, RpcResult<Void>>() {
350
351         @Override
352         public RpcResult<Void> apply(Void input) {
353             return RpcResultBuilder.<Void>success().build();
354         }
355     };
356 }