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