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