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