Merge "Code coverage increasing for faas-renderer"
[groupbasedpolicy.git] / renderers / faas / src / main / java / org / opendaylight / groupbasedpolicy / renderer / faas / FaasEndpointManagerListener.java
1 /*
2  * Copyright (c) 2015 Huawei Technologies 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.renderer.faas;
10
11 import static com.google.common.base.Preconditions.checkNotNull;
12
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.UUID;
17 import java.util.concurrent.ScheduledExecutorService;
18
19 import com.google.common.annotations.VisibleForTesting;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
22 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
23 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
24 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
25 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.faas.uln.datastore.api.UlnDatastoreApi;
28 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
29 import org.opendaylight.groupbasedpolicy.util.IidFactory;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.faas.endpoint.rev151009.FaasEndpointContext;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.common.rev151013.Text;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.common.rev151013.Uuid;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.endpoints.locations.rev151013.endpoints.locations.container.endpoints.locations.EndpointLocationBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.ports.rev151013.ports.container.ports.port.PrivateIps;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.faas.logical.faas.ports.rev151013.ports.container.ports.port.PrivateIpsBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedEndpoint;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedEndpointBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedEndpointKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.faas.rev151009.mapped.tenants.entities.mapped.entity.MappedSubnet;
48 import org.opendaylight.yangtools.concepts.ListenerRegistration;
49 import org.opendaylight.yangtools.yang.binding.DataObject;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 import com.google.common.base.Optional;
55
56 public class FaasEndpointManagerListener implements DataChangeListener, AutoCloseable {
57
58     private static final Logger LOG = LoggerFactory.getLogger(FaasEndpointManagerListener.class);
59     private final ScheduledExecutorService executor;
60     private final ListenerRegistration<DataChangeListener> registerListener;
61     private final FaasPolicyManager policyManager;
62     private final DataBroker dataProvider;
63
64     public FaasEndpointManagerListener(FaasPolicyManager policyManager, DataBroker dataProvider,
65             ScheduledExecutorService executor) {
66         this.executor = executor;
67         this.policyManager = policyManager;
68         this.dataProvider = dataProvider;
69         this.registerListener = checkNotNull(dataProvider).registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
70                 IidFactory.endpointsIidWildcard(), this, AsyncDataBroker.DataChangeScope.SUBTREE);
71     }
72
73     @Override
74     public void close() throws Exception {
75         if (registerListener != null)
76             registerListener.close();
77     }
78
79     @Override
80     public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
81         executor.execute(new Runnable() {
82
83             public void run() {
84                 executeEvent(change);
85             }
86         });
87     }
88
89     @VisibleForTesting
90     void executeEvent(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
91
92         // Create
93         for (DataObject dao : change.getCreatedData().values()) {
94             if (dao instanceof Endpoint) {
95                 Endpoint endpoint = (Endpoint) dao;
96                 LOG.debug("Created Endpoint {}", endpoint);
97                 if (validate(endpoint)) {
98                     policyManager.registerTenant(endpoint.getTenant(), endpoint.getEndpointGroup());
99                     processEndpoint(endpoint);
100                 }
101             } else if (dao instanceof EndpointL3) {
102                 LOG.debug("Created EndpointL3 {}", dao);
103             } else if (dao instanceof EndpointL3Prefix) {
104                 LOG.warn("Not Handled Event Yet by Faas Renderer. Created EndpointL3Prefix {}", dao);
105             }
106         }
107         // Update
108         Map<InstanceIdentifier<?>, DataObject> dao = change.getUpdatedData();
109         for (Map.Entry<InstanceIdentifier<?>, DataObject> entry : dao.entrySet()) {
110             if (entry.getValue() instanceof Endpoint) {
111                 Endpoint endpoint = (Endpoint) entry.getValue();
112                 LOG.debug("Updated Endpoint {}", endpoint);
113                 if (validate(endpoint)) {
114                     policyManager.registerTenant(endpoint.getTenant(), endpoint.getEndpointGroup());
115                     processEndpoint(endpoint);
116                 }
117             } else if (entry.getValue() instanceof EndpointL3) {
118                 LOG.debug("Updated EndpointL3 {}", entry.getValue());
119             } else if (entry.getValue() instanceof EndpointL3Prefix) {
120                 LOG.warn("Not Handled Event Yet by Faas Renderer. Updated EndpointL3Prefix {}", entry.getValue());
121             }
122         }
123         // Remove
124         for (InstanceIdentifier<?> iid : change.getRemovedPaths()) {
125             DataObject old = change.getOriginalData().get(iid);
126             if (old == null) {
127                 continue;
128             }
129             if (old instanceof Endpoint) {
130                 Endpoint endpoint = (Endpoint) old;
131                 LOG.debug("Removed Endpoint {}", endpoint);
132                 removeFaasEndpointLocationIfExist(endpoint.getTenant(), endpoint.getL2Context(),
133                         endpoint.getMacAddress());
134             } else if (old instanceof EndpointL3) {
135                 EndpointL3 endpoint = (EndpointL3) old;
136                 LOG.debug("Removed EndpointL3 {}", endpoint);
137                 removeFaasEndpointLocationIfExist(endpoint.getTenant(), endpoint.getL2Context(),
138                         endpoint.getMacAddress());
139             } else if (old instanceof EndpointL3Prefix) {
140                 LOG.warn("Not Handled Event Yet by Faas Renderer. Removed EndpointL3Prefix {}", old);
141             }
142         }
143     }
144
145     protected void processEndpoint(Endpoint endpoint) {
146         Uuid tenantId = policyManager.getFaasTenantId(endpoint.getTenant());
147         if (tenantId == null) {
148             LOG.error("Failed Endpoint Registration. Couldn't find faas tenant Id. Endpoint {}", endpoint);
149             return;
150         }
151         EndpointLocationBuilder epLocBuilder = new EndpointLocationBuilder();
152         epLocBuilder.setDescription(new Text("gbp-endpoint"));
153         epLocBuilder.setName(new Text(endpoint.getL2Context().getValue()));
154         epLocBuilder.setTenantId(tenantId);
155         epLocBuilder.setFaasPortRefId(endpoint.getAugmentation(FaasEndpointContext.class).getFaasPortRefId());
156         Uuid epId = getFaasEndpointId(endpoint);
157         if (epId == null) {
158             LOG.error("Failed Endpoint registration. Couldn't Create Faas Endpoint Id");
159             return;
160         }
161         epLocBuilder.setUuid(epId);
162         Uuid faasSubnetId = getFaasSubnetId(endpoint);
163         List<PrivateIps> privateIpAddresses = new ArrayList<>();
164         for (L3Address ip : endpoint.getL3Address()) {
165             PrivateIpsBuilder ipBuilder = new PrivateIpsBuilder();
166             ipBuilder.setIpAddress(ip.getIpAddress());
167             ipBuilder.setSubnetId(faasSubnetId);
168             privateIpAddresses.add(ipBuilder.build());
169         }
170         if (!UlnDatastoreApi.attachEndpointToSubnet(epLocBuilder, faasSubnetId, endpoint.getMacAddress(),
171                 privateIpAddresses, null)) {
172             LOG.error("Failed Endpoint Registration. Failed to Attach Endpoint to Faas Logical Network. Endpoint {}",
173                     endpoint);
174         }
175     }
176
177     private Uuid getFaasEndpointId(Endpoint endpoint) {
178         MappedEndpoint mEndpoint1 = getMappedEndpoint(endpoint);
179         if (mEndpoint1 != null) {
180             return mEndpoint1.getEndpointLocation();
181         }
182         synchronized (this) {// must be atomic
183             MappedEndpoint mEndpoint2 = getMappedEndpoint(endpoint);
184             if (mEndpoint2 != null) {
185                 return mEndpoint2.getEndpointLocation();
186             }
187             MappedEndpointBuilder mBuilder = new MappedEndpointBuilder();
188             mBuilder.setL2Context(endpoint.getL2Context());
189             mBuilder.setMacAddress(endpoint.getMacAddress());
190             mBuilder.setEndpointLocation(new Uuid(UUID.randomUUID().toString()));
191             MappedEndpoint mEndpoint = mBuilder.build();
192             WriteTransaction wTx = dataProvider.newWriteOnlyTransaction();
193             wTx.put(LogicalDatastoreType.OPERATIONAL, FaasIidFactory.mappedEndpointIid(
194                     endpoint.getTenant(), new MappedEndpointKey(endpoint.getL2Context(), endpoint.getMacAddress())),
195                     mEndpoint);
196             if (DataStoreHelper.submitToDs(wTx)) {
197                 LOG.debug("Cached in Datastore Mapped Endpoint {}", mEndpoint);
198                 return mEndpoint.getEndpointLocation();
199             } else {
200                 LOG.error("Couldn't Cache in Datastore Mapped Endpoint {}", mEndpoint);
201                 return null;
202             }
203         }
204     }
205
206     private Uuid getFaasSubnetId(Endpoint endpoint) {
207         if (endpoint.getEndpointGroup() == null) {
208             LOG.error("Failed Endpoint registration -- No Endpoint-Group Id in endpoint {}", endpoint);
209             return null;
210         }
211         SubnetId subnetId = null;
212         if (endpoint.getNetworkContainment() != null) {
213             LOG.trace("Subnet is defined based on endpoint containment value {}", endpoint.getNetworkContainment()
214                 .getValue());
215             subnetId = new SubnetId(endpoint.getNetworkContainment());
216         }
217         if (subnetId == null) {
218             LOG.error("Failed Endpoint registration -- Couldn't find a subnet for endpoint {}", endpoint.getKey());
219             return null;
220         }
221         LOG.debug("Using subnetId {} for endpoint {}", subnetId, endpoint.getKey());
222         policyManager.registerSubnetWithEpg(endpoint.getEndpointGroup(), endpoint.getTenant(), subnetId);
223
224         Optional<MappedSubnet> subnetOp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
225                 FaasIidFactory.mappedSubnetIid(endpoint.getTenant(), subnetId),
226                 dataProvider.newReadWriteTransaction());
227         if (subnetOp.isPresent()) {
228             return subnetOp.get().getFaasSubnetId();
229         }
230         LOG.error("Failed Endpoint registration -- Couldn't find Mapped Subnet Id based on GBP Subnet Id {}", subnetId);
231         return null;
232     }
233
234     private boolean validate(Endpoint endpoint) {
235         if (endpoint.getL2Context() == null) {
236             LOG.error("Endpoint Failed Validation -- Missing L2 Context. Endpoint {}", endpoint);
237             return false;
238         }
239         if (endpoint.getL3Address() == null) {
240             LOG.error("Endpoint Failed Validation -- Missing L3 Address. Endpoint {}", endpoint);
241             return false;
242         }
243         if (endpoint.getMacAddress() == null) {
244             LOG.error("Endpoint Failed Validation -- Missing Mac Address. Endpoint {}", endpoint);
245             return false;
246         }
247         if (endpoint.getTenant() == null) {
248             LOG.error("Endpoint Failed Validation -- Missing Tenant Id. Endpoint {}", endpoint);
249             return false;
250         }
251         if (endpoint.getEndpointGroup() == null) {
252             LOG.error("Endpoint Failed Validation -- Missing Endpoint-Group. Endpoint {}", endpoint);
253             return false;
254         }
255         FaasEndpointContext faasEpAug = endpoint.getAugmentation(FaasEndpointContext.class);
256         if (faasEpAug == null || faasEpAug.getFaasPortRefId() == null) {
257             LOG.error("Endpoint Failed Validation -- Missing Required Faas Info. Endpoint {}", endpoint);
258             return false;
259         }
260         return true;
261     }
262
263     private void removeFaasEndpointLocationIfExist(TenantId tenantId, L2BridgeDomainId l2BridgeDomainId,
264             MacAddress macAddress) {
265         synchronized (this) {
266             MappedEndpointKey mappedEndpointKey = new MappedEndpointKey(l2BridgeDomainId, macAddress);
267             ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
268             Optional<MappedEndpoint> endpointOp = DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
269                     FaasIidFactory.mappedEndpointIid(tenantId, mappedEndpointKey), rwTx);
270             DataStoreHelper.submitToDs(rwTx);
271             if (endpointOp.isPresent()) {
272                 UlnDatastoreApi.removeEndpointLocationFromDsIfExists(policyManager.getFaasTenantId(tenantId),
273                         endpointOp.get().getEndpointLocation());
274             }
275         }
276     }
277
278     private MappedEndpoint getMappedEndpoint(Endpoint endpoint) {
279         MappedEndpointKey mappedEndpointKey = new MappedEndpointKey(endpoint.getL2Context(), endpoint.getMacAddress());
280         Optional<MappedEndpoint> endpointOp = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
281                 FaasIidFactory.mappedEndpointIid(endpoint.getTenant(), mappedEndpointKey),
282                 dataProvider.newReadWriteTransaction());
283         if (endpointOp.isPresent()) {
284             return endpointOp.get();
285         }
286         return null;
287     }
288 }