Handle nullable lists in neutronvpn
[netvirt.git] / neutronvpn / impl / src / main / java / org / opendaylight / netvirt / neutronvpn / evpn / manager / NeutronEvpnManager.java
1 /*
2  * Copyright © 2017 Ericsson India Global Services Pvt Ltd. 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 package org.opendaylight.netvirt.neutronvpn.evpn.manager;
9
10 import static org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils.requireNonNullElse;
11
12 import com.google.common.base.Optional;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import com.google.common.util.concurrent.SettableFuture;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.function.Consumer;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
22 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
23 import org.opendaylight.netvirt.neutronvpn.NeutronvpnManager;
24 import org.opendaylight.netvirt.neutronvpn.NeutronvpnUtils;
25 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
26 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
27 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateEVPNInput;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateEVPNOutput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateEVPNOutputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteEVPNInput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteEVPNOutput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteEVPNOutputBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetEVPNInput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetEVPNOutput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetEVPNOutputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.VpnMaps;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.createevpn.input.Evpn;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.getevpn.output.EvpnInstances;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.getevpn.output.EvpnInstancesBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMap;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMapKey;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
45 import org.opendaylight.yangtools.yang.common.RpcError;
46 import org.opendaylight.yangtools.yang.common.RpcResult;
47 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50 import org.slf4j.helpers.FormattingTuple;
51 import org.slf4j.helpers.MessageFormatter;
52
53
54 public class NeutronEvpnManager {
55     private static final Logger LOG = LoggerFactory.getLogger(NeutronEvpnManager.class);
56     private final DataBroker dataBroker;
57     private final NeutronvpnManager neutronvpnManager;
58     private final NeutronvpnUtils neutronvpnUtils;
59
60     public NeutronEvpnManager(DataBroker dataBroker, NeutronvpnManager neutronvpnManager,
61             NeutronvpnUtils neutronvpnUtils) {
62         this.dataBroker = dataBroker;
63         this.neutronvpnManager = neutronvpnManager;
64         this.neutronvpnUtils = neutronvpnUtils;
65     }
66
67     @SuppressWarnings("checkstyle:IllegalCatch")
68     public ListenableFuture<RpcResult<CreateEVPNOutput>> createEVPN(CreateEVPNInput input) {
69         CreateEVPNOutputBuilder opBuilder = new CreateEVPNOutputBuilder();
70         SettableFuture<RpcResult<CreateEVPNOutput>> result = SettableFuture.create();
71         List<RpcError> errorList = new ArrayList<>();
72         int failurecount = 0;
73         List<String> existingRDs = neutronvpnUtils.getExistingRDs();
74
75         for (Evpn vpn : requireNonNullElse(input.getEvpn(), Collections.<Evpn>emptyList())) {
76             if (vpn.getRouteDistinguisher() == null || vpn.getImportRT() == null || vpn.getExportRT() == null) {
77                 errorList.add(RpcResultBuilder.newWarning(RpcError.ErrorType.PROTOCOL, "invalid-input",
78                         formatAndLog(LOG::warn, "Creation of EVPN failed for VPN {} due to absence of RD/iRT/eRT input",
79                                 vpn.getId().getValue())));
80                 continue;
81             }
82             VpnInstance.Type vpnInstanceType = VpnInstance.Type.L2;
83             if (vpn.getRouteDistinguisher().size() > 1) {
84                 errorList.add(RpcResultBuilder.newWarning(RpcError.ErrorType.PROTOCOL, "invalid-input",
85                         formatAndLog(LOG::warn, "Creation of EVPN failed for VPN {} due to multiple RD input {}",
86                                 vpn.getId().getValue(), vpn.getRouteDistinguisher())));
87                 continue;
88             }
89             if (existingRDs.contains(vpn.getRouteDistinguisher().get(0))) {
90                 errorList.add(RpcResultBuilder.newWarning(RpcError.ErrorType.PROTOCOL, "invalid-input",
91                         formatAndLog(LOG::warn,
92                                 "Creation of EVPN failed for VPN {} as another VPN with the same RD {} is already "
93                                         + "configured",
94                                 vpn.getId().getValue(), vpn.getRouteDistinguisher().get(0))));
95                 continue;
96             }
97             try {
98                 neutronvpnManager.createVpn(vpn.getId(), vpn.getName(), vpn.getTenantId(), vpn.getRouteDistinguisher(),
99                         vpn.getImportRT(), vpn.getExportRT(), null /*router-id*/, null /*network-id*/,
100                         vpnInstanceType, 0 /*l2vni*/);
101             } catch (Exception ex) {
102                 errorList.add(RpcResultBuilder.newError(RpcError.ErrorType.APPLICATION,
103                         formatAndLog(LOG::error, "Creation of EVPN failed for VPN {}", vpn.getId().getValue(), ex),
104                         ex.getMessage()));
105                 failurecount++;
106             }
107         }
108         if (failurecount != 0) {
109             result.set(RpcResultBuilder.<CreateEVPNOutput>failed().withRpcErrors(errorList).build());
110         } else {
111             List<String> errorResponseList = new ArrayList<>();
112             if (!errorList.isEmpty()) {
113                 for (RpcError rpcError : errorList) {
114                     errorResponseList.add("ErrorType: " + rpcError.getErrorType() + ", ErrorTag: " + rpcError.getTag()
115                             + ", ErrorMessage: " + rpcError.getMessage());
116                 }
117             } else {
118                 errorResponseList.add("EVPN creation successful with no errors");
119             }
120             opBuilder.setResponse(errorResponseList);
121             result.set(RpcResultBuilder.success(opBuilder.build()).build());
122         }
123         return result;
124     }
125
126     public ListenableFuture<RpcResult<GetEVPNOutput>> getEVPN(GetEVPNInput input) {
127         GetEVPNOutputBuilder opBuilder = new GetEVPNOutputBuilder();
128         SettableFuture<RpcResult<GetEVPNOutput>> result = SettableFuture.create();
129         Uuid inputVpnId = input.getId();
130         List<VpnInstance> vpns = new ArrayList<>();
131         if (inputVpnId == null) {
132             vpns = VpnHelper.getAllVpnInstances(dataBroker);
133             if (!vpns.isEmpty()) {
134                 for (VpnInstance vpn : vpns) {
135                     if (vpn.getIpv4Family().getRouteDistinguisher() != null
136                             && vpn.getType() == VpnInstance.Type.L2) {
137                         vpns.add(vpn);
138                     }
139                 }
140             } else {
141                 // No VPN present
142                 result.set(RpcResultBuilder.success(opBuilder.build()).build());
143                 return result;
144             }
145         } else {
146             String name = inputVpnId.getValue();
147             VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, name);
148             if (vpnInstance != null && vpnInstance.getIpv4Family().getRouteDistinguisher() != null
149                     && vpnInstance.getType() == VpnInstance.Type.L2) {
150                 vpns.add(vpnInstance);
151             } else {
152                 result.set(RpcResultBuilder.<GetEVPNOutput>failed().withWarning(RpcError.ErrorType.PROTOCOL,
153                         "invalid-value",
154                         formatAndLog(LOG::error, "GetEVPN failed because VPN {} is not present", name)).build());
155             }
156         }
157         List<EvpnInstances> evpnList = new ArrayList<>();
158         for (VpnInstance vpnInstance : vpns) {
159             Uuid vpnId = new Uuid(vpnInstance.getVpnInstanceName());
160             InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class).child(VpnMap
161                     .class, new VpnMapKey(vpnId)).build();
162             EvpnInstancesBuilder evpn = new EvpnInstancesBuilder();
163             List<String> rd = vpnInstance.getIpv4Family().getRouteDistinguisher();
164             List<String> ertList = new ArrayList<>();
165             List<String> irtList = new ArrayList<>();
166             for (VpnTarget vpnTarget : requireNonNullElse(vpnInstance.getIpv4Family().getVpnTargets().getVpnTarget(),
167                     Collections.<VpnTarget>emptyList())) {
168                 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
169                     ertList.add(vpnTarget.getVrfRTValue());
170                 }
171                 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
172                     irtList.add(vpnTarget.getVrfRTValue());
173                 }
174                 if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
175                     ertList.add(vpnTarget.getVrfRTValue());
176                     irtList.add(vpnTarget.getVrfRTValue());
177                 }
178             }
179             evpn.setId(vpnId).setRouteDistinguisher(rd).setImportRT(irtList).setExportRT(ertList);
180             try {
181                 Optional<VpnMap> optionalVpnMap =
182                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
183                                 vpnMapIdentifier);
184                 if (optionalVpnMap.isPresent()) {
185                     VpnMap vpnMap = optionalVpnMap.get();
186                     evpn.setTenantId(vpnMap.getTenantId()).setName(vpnMap.getName());
187                 }
188             } catch (ReadFailedException e) {
189                 LOG.error("Error reading the VPN map for {}", vpnMapIdentifier, e);
190                 result.set(RpcResultBuilder.<GetEVPNOutput>failed().withError(RpcError.ErrorType.APPLICATION,
191                         "Error reading the VPN map for " + vpnMapIdentifier, e).build());
192                 return result;
193             }
194             evpnList.add(evpn.build());
195         }
196
197         opBuilder.setEvpnInstances(evpnList);
198         result.set(RpcResultBuilder.success(opBuilder.build()).build());
199         return result;
200     }
201
202     public ListenableFuture<RpcResult<DeleteEVPNOutput>> deleteEVPN(DeleteEVPNInput input) {
203         List<RpcError> errorList = new ArrayList<>();
204
205         for (Uuid vpn : requireNonNullElse(input.getId(), Collections.<Uuid>emptyList())) {
206             VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpn.getValue());
207             if (vpnInstance != null) {
208                 neutronvpnManager.removeVpn(vpn);
209             } else {
210                 errorList.add(RpcResultBuilder.newWarning(RpcError.ErrorType.PROTOCOL, "invalid-value",
211                         formatAndLog(LOG::warn, "EVPN with vpnid: {} does not exist", vpn.getValue())));
212             }
213         }
214         List<String> errorResponseList = new ArrayList<>();
215         if (!errorList.isEmpty()) {
216             for (RpcError rpcError : errorList) {
217                 errorResponseList.add("ErrorType: " + rpcError.getErrorType() + ", ErrorTag: " + rpcError.getTag()
218                         + ", ErrorMessage: " + rpcError.getMessage());
219             }
220         } else {
221             errorResponseList.add("Deletion of EVPN operation successful");
222         }
223         DeleteEVPNOutputBuilder opBuilder = new DeleteEVPNOutputBuilder();
224         opBuilder.setResponse(errorResponseList);
225         SettableFuture<RpcResult<DeleteEVPNOutput>> result = SettableFuture.create();
226         result.set(RpcResultBuilder.success(opBuilder.build()).build());
227         return result;
228     }
229
230     private String formatAndLog(Consumer<String> logger, String template, Object arg) {
231         return logAndReturnMessage(logger, MessageFormatter.format(template, arg));
232     }
233
234     private String formatAndLog(Consumer<String> logger, String template, Object arg1, Object arg2) {
235         return logAndReturnMessage(logger, MessageFormatter.format(template, arg1, arg2));
236     }
237
238     private String logAndReturnMessage(Consumer<String> logger, FormattingTuple tuple) {
239         String message = tuple.getMessage();
240         logger.accept(message);
241         return message;
242     }
243 }