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