Handle nullable lists
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / impl / ItmProvider.java
1 /*
2  * Copyright (c) 2016, 2018 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.genius.itm.impl;
9
10 import static org.opendaylight.genius.itm.impl.ItmUtils.nullToEmpty;
11
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import java.math.BigInteger;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.concurrent.ExecutionException;
20 import java.util.regex.Matcher;
21 import java.util.regex.Pattern;
22 import javax.annotation.PostConstruct;
23 import javax.annotation.PreDestroy;
24 import javax.inject.Inject;
25 import javax.inject.Singleton;
26 import org.apache.aries.blueprint.annotation.service.Service;
27 import org.apache.felix.service.command.CommandSession;
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
31 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
32 import org.opendaylight.genius.itm.api.IITMProvider;
33 import org.opendaylight.genius.itm.cache.DpnTepStateCache;
34 import org.opendaylight.genius.itm.cache.TunnelStateCache;
35 import org.opendaylight.genius.itm.cli.TepCommandHelper;
36 import org.opendaylight.genius.itm.cli.TepException;
37 import org.opendaylight.genius.itm.diagstatus.ItmDiagStatusProvider;
38 import org.opendaylight.genius.itm.globals.ITMConstants;
39 import org.opendaylight.genius.itm.listeners.InterfaceStateListener;
40 import org.opendaylight.genius.itm.listeners.OvsdbNodeListener;
41 import org.opendaylight.genius.itm.listeners.TransportZoneListener;
42 import org.opendaylight.genius.itm.listeners.TunnelMonitorChangeListener;
43 import org.opendaylight.genius.itm.listeners.TunnelMonitorIntervalListener;
44 import org.opendaylight.genius.itm.listeners.VtepConfigSchemaListener;
45 import org.opendaylight.genius.itm.monitoring.ItmTunnelEventListener;
46 import org.opendaylight.genius.itm.rpc.ItmManagerRpcService;
47 import org.opendaylight.genius.mdsalutil.MDSALUtil;
48 import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
49 import org.opendaylight.infrautils.diagstatus.ServiceState;
50 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
51 import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
52 import org.opendaylight.mdsal.eos.binding.api.Entity;
53 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipCandidateRegistration;
54 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
55 import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolOutput;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.ItmConfig;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.VtepConfigSchemas;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.vtep.config.schemas.VtepConfigSchema;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.vtep.config.schemas.VtepConfigSchemaBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddExternalTunnelEndpointInput;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddExternalTunnelEndpointInputBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveExternalTunnelEndpointInput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveExternalTunnelEndpointInputBuilder;
72 import org.opendaylight.yangtools.yang.common.RpcResult;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
75
76 @Singleton
77 @Service
78 public class ItmProvider implements AutoCloseable, IITMProvider /*,ItmStateService */ {
79
80     private static final Logger LOG = LoggerFactory.getLogger(ItmProvider.class);
81
82     private final DataBroker dataBroker;
83     private final ItmManagerRpcService itmRpcService ;
84     private final IdManagerService idManager;
85     private final TepCommandHelper tepCommandHelper;
86     private final TransportZoneListener tzChangeListener;
87     private final TunnelMonitorChangeListener tnlToggleListener;
88     private final TunnelMonitorIntervalListener tnlIntervalListener;
89     private final VtepConfigSchemaListener vtepConfigSchemaListener;
90     private final InterfaceStateListener ifStateListener;
91     private final EntityOwnershipService entityOwnershipService;
92     private final ItmDiagStatusProvider itmStatusProvider;
93     private RpcProviderRegistry rpcProviderRegistry;
94     private final ItmTunnelEventListener itmStateListener;
95     private final OvsdbNodeListener ovsdbChangeListener;
96     static short flag = 0;
97     private final TunnelMonitoringConfig tunnelMonitoringConfig;
98     private EntityOwnershipCandidateRegistration registryCandidate;
99     private final DpnTepStateCache dpnTepStateCache;
100     private final TunnelStateCache tunnelStateCache;
101     private final ItmConfig itmConfig;
102     private final JobCoordinator jobCoordinator;
103     private final EntityOwnershipUtils entityOwnershipUtils;
104
105     @Inject
106     public ItmProvider(DataBroker dataBroker,
107                        IdManagerService idManagerService,
108                        InterfaceStateListener interfaceStateListener,
109                        ItmManagerRpcService itmManagerRpcService,
110                        ItmTunnelEventListener itmTunnelEventListener,
111                        TepCommandHelper tepCommandHelper,
112                        TunnelMonitorChangeListener tunnelMonitorChangeListener,
113                        TunnelMonitorIntervalListener tunnelMonitorIntervalListener,
114                        TransportZoneListener transportZoneListener,
115                        VtepConfigSchemaListener vtepConfigSchemaListener,
116                        OvsdbNodeListener ovsdbNodeListener,
117                        TunnelMonitoringConfig tunnelMonitoringConfig,
118                        EntityOwnershipService entityOwnershipService,
119                        DpnTepStateCache dpnTepStateCache,
120                        final ItmDiagStatusProvider itmDiagStatusProvider,
121                        final TunnelStateCache tunnelStateCache,
122                        final ItmConfig itmConfig,
123                        final JobCoordinator jobCoordinator,
124                        final EntityOwnershipUtils entityOwnershipUtils) {
125         LOG.info("ItmProvider Before register MBean");
126         this.dataBroker = dataBroker;
127         this.idManager = idManagerService;
128         this.ifStateListener = interfaceStateListener;
129         this.itmRpcService = itmManagerRpcService;
130         this.itmStateListener = itmTunnelEventListener;
131         this.tepCommandHelper = tepCommandHelper;
132         this.tnlToggleListener = tunnelMonitorChangeListener;
133         this.tnlIntervalListener = tunnelMonitorIntervalListener;
134         this.tzChangeListener = transportZoneListener;
135         this.vtepConfigSchemaListener = vtepConfigSchemaListener;
136         this.ovsdbChangeListener = ovsdbNodeListener;
137         this.tunnelMonitoringConfig = tunnelMonitoringConfig;
138         this.entityOwnershipService = entityOwnershipService;
139         this.dpnTepStateCache = dpnTepStateCache;
140         this.itmStatusProvider = itmDiagStatusProvider;
141         this.tunnelStateCache = tunnelStateCache;
142         ITMBatchingUtils.registerWithBatchManager(this.dataBroker);
143
144         this.itmConfig = itmConfig;
145         this.jobCoordinator = jobCoordinator;
146         this.entityOwnershipUtils = entityOwnershipUtils;
147     }
148
149     @PostConstruct
150     @SuppressWarnings("checkstyle:IllegalCatch")
151     public void start() {
152         try {
153             createIdPool();
154             registerEntityForOwnership();
155             itmStatusProvider.reportStatus(ServiceState.OPERATIONAL);
156             LOG.info("ItmProvider Started");
157         } catch (Exception ex) {
158             itmStatusProvider.reportStatus(ex);
159             LOG.info("ItmProvider failed to start", ex);
160             return;
161         }
162         createDefaultTransportZone(itmConfig);
163     }
164
165     public void createDefaultTransportZone(ItmConfig itmConfigObj) {
166         if (!entityOwnershipUtils.isEntityOwner(ITMConstants.ITM_CONFIG_ENTITY, ITMConstants.ITM_CONFIG_ENTITY)) {
167             return;
168         }
169         jobCoordinator.enqueueJob(ITMConstants.DEFAULT_TRANSPORT_ZONE, () -> {
170             boolean defTzEnabled = itmConfigObj.isDefTzEnabled();
171             if (defTzEnabled) {
172                 String tunnelType = itmConfigObj.getDefTzTunnelType();
173                 if (tunnelType == null || tunnelType.isEmpty()) {
174                     tunnelType = ITMConstants.TUNNEL_TYPE_VXLAN;
175                 }
176                 // validate tunnel-type and based on tunnel-type,
177                 // create default-TZ or update default-TZ if tunnel-type is changed during ODL restart
178                 configureTunnelType(ITMConstants.DEFAULT_TRANSPORT_ZONE, tunnelType);
179                 LOG.info("{} is created with {} tunnel-type.", ITMConstants.DEFAULT_TRANSPORT_ZONE, tunnelType);
180             } else {
181                 LOG.info("Removing {} on start-up, def-tz-enabled is false.", ITMConstants.DEFAULT_TRANSPORT_ZONE);
182                 // check if default-TZ already exists, then delete it because flag is OFF now.
183                 ItmUtils.deleteTransportZoneFromConfigDS(ITMConstants.DEFAULT_TRANSPORT_ZONE, dataBroker);
184             }
185             return Collections.emptyList();
186         });
187     }
188
189     private void registerEntityForOwnership() {
190         try {
191             this.registryCandidate = entityOwnershipService
192                     .registerCandidate(new Entity(ITMConstants.ITM_CONFIG_ENTITY, ITMConstants.ITM_CONFIG_ENTITY));
193         } catch (CandidateAlreadyRegisteredException e) {
194             LOG.error("failed to register entity {} for entity-ownership-service", e.getEntity());
195         }
196     }
197
198     @Override
199     @PreDestroy
200     public void close() {
201         if (tzChangeListener != null) {
202             tzChangeListener.close();
203         }
204         if (tnlIntervalListener != null) {
205             tnlIntervalListener.close();
206         }
207         if (tnlToggleListener != null) {
208             tnlToggleListener.close();
209         }
210         if (ovsdbChangeListener != null) {
211             ovsdbChangeListener.close();
212         }
213         if (registryCandidate != null) {
214             registryCandidate.close();
215         }
216         itmStatusProvider.reportStatus(ServiceState.UNREGISTERED);
217         LOG.info("ItmProvider Closed");
218     }
219
220     private void createIdPool() {
221         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
222                 .setPoolName(ITMConstants.ITM_IDPOOL_NAME)
223                 .setLow(ITMConstants.ITM_IDPOOL_START)
224                 .setHigh(new BigInteger(ITMConstants.ITM_IDPOOL_SIZE).longValue())
225                 .build();
226         try {
227             ListenableFuture<RpcResult<CreateIdPoolOutput>> result = idManager.createIdPool(createPool);
228             if (result != null && result.get().isSuccessful()) {
229                 LOG.debug("Created IdPool for ITM Service");
230             }
231         } catch (InterruptedException | ExecutionException e) {
232             LOG.error("Failed to create idPool for ITM Service ", e);
233         }
234     }
235
236     @Override
237     public DataBroker getDataBroker() {
238         return dataBroker;
239     }
240
241     @Override
242     public void addExternalEndpoint(Class<? extends TunnelTypeBase> tunnelType, IpAddress dcgwIP) {
243         AddExternalTunnelEndpointInput addExternalTunnelEndpointInput =
244                 new AddExternalTunnelEndpointInputBuilder().setTunnelType(tunnelType)
245                         .setDestinationIp(dcgwIP).build();
246         JdkFutures.addErrorLogging(itmRpcService.addExternalTunnelEndpoint(addExternalTunnelEndpointInput),
247                 LOG, "addExternalTunnelEndpoint");
248     }
249
250     @Override
251     public void remExternalEndpoint(Class<? extends TunnelTypeBase> tunnelType, IpAddress dcgwIP) {
252         RemoveExternalTunnelEndpointInput removeExternalTunnelEndpointInput =
253                 new RemoveExternalTunnelEndpointInputBuilder().setTunnelType(tunnelType)
254                         .setDestinationIp(dcgwIP).build();
255         JdkFutures.addErrorLogging(itmRpcService.removeExternalTunnelEndpoint(removeExternalTunnelEndpointInput),
256                 LOG, "removeExternalTunnelEndpoint");
257     }
258
259     @Override
260     public void createLocalCache(BigInteger dpnId, String portName, Integer vlanId, String ipAddress, String subnetMask,
261                                  String gatewayIp, String transportZone, CommandSession session) {
262         if (tepCommandHelper != null) {
263             try {
264                 tepCommandHelper.createLocalCache(dpnId, portName, vlanId, ipAddress, subnetMask,
265                         gatewayIp, transportZone, session);
266             } catch (TepException e) {
267                 LOG.error("Create Local Cache failed", e);
268             }
269         } else {
270             LOG.trace("tepCommandHelper doesnt exist");
271         }
272     }
273
274     @Override
275     public void commitTeps() {
276         tepCommandHelper.deleteOnCommit();
277         tepCommandHelper.buildTeps();
278     }
279
280     @Override
281     public void showTeps(CommandSession session) {
282         try {
283             tepCommandHelper.showTeps(tunnelMonitoringConfig.isTunnelMonitoringEnabled(),
284                     tunnelMonitoringConfig.getMonitorInterval(), session);
285         } catch (TepException e) {
286             LOG.error("show teps failed", e);
287         }
288     }
289
290     @Override
291     public void showState(Collection<StateTunnelList> tunnels) {
292         if (tunnels != null) {
293             try {
294                 tepCommandHelper.showState(tunnels, tunnelMonitoringConfig.isTunnelMonitoringEnabled());
295             } catch (TepException e) {
296                 LOG.error("show state failed", e);
297             }
298         } else {
299             LOG.debug("No tunnels available");
300         }
301     }
302
303     @Override
304     public void showCache(String cacheName) {
305         tepCommandHelper.showCache(cacheName);
306     }
307
308     @Override
309     public void deleteVtep(BigInteger dpnId, String portName, Integer vlanId, String ipAddress, String subnetMask,
310                            String gatewayIp, String transportZone, CommandSession session) {
311         try {
312             tepCommandHelper.deleteVtep(dpnId,  portName, vlanId, ipAddress,
313                     subnetMask, gatewayIp, transportZone, session);
314         } catch (TepException e) {
315             LOG.error("Delete Vteps Failed", e);
316         }
317     }
318
319     @Override
320     public void configureTunnelType(String transportZone, String tunnelType) {
321         LOG.debug("ItmProvider: configureTunnelType {} for transportZone {}", tunnelType, transportZone);
322         try {
323             tepCommandHelper.configureTunnelType(transportZone,tunnelType);
324         } catch (ExecutionException | InterruptedException e) {
325             LOG.error("configureTunnelType {} failed for transportZone {}", tunnelType, transportZone, e);
326         }
327     }
328
329     @Override
330     public void addVtepConfigSchema(VtepConfigSchema vtepConfigSchema) {
331         VtepConfigSchema validatedSchema = ItmUtils.validateForAddVtepConfigSchema(vtepConfigSchema,
332                 getAllVtepConfigSchemas());
333
334         String schemaName = validatedSchema.getSchemaName();
335         VtepConfigSchema existingSchema = getVtepConfigSchema(schemaName);
336         Preconditions.checkArgument(existingSchema == null, "VtepConfigSchema [" + schemaName + "] already exists!");
337         MDSALUtil.syncWrite(this.dataBroker, LogicalDatastoreType.CONFIGURATION,
338                 ItmUtils.getVtepConfigSchemaIdentifier(schemaName), validatedSchema);
339         LOG.debug("Vtep config schema {} added to config DS", schemaName);
340     }
341
342     @Override
343     public VtepConfigSchema getVtepConfigSchema(String schemaName) {
344         return ItmUtils.read(LogicalDatastoreType.CONFIGURATION, ItmUtils.getVtepConfigSchemaIdentifier(schemaName),
345                 this.dataBroker).orNull();
346     }
347
348     @Override
349     public List<VtepConfigSchema> getAllVtepConfigSchemas() {
350         return ItmUtils.read(LogicalDatastoreType.CONFIGURATION, ItmUtils.getVtepConfigSchemasIdentifier(),
351                 this.dataBroker).toJavaUtil().map(VtepConfigSchemas::getVtepConfigSchema).orElse(null);
352     }
353
354     @Override
355     public void updateVtepSchema(String schemaName, List<BigInteger> lstDpnsForAdd, List<BigInteger> lstDpnsForDelete) {
356         LOG.trace("Updating VTEP schema {} by adding DPN's {} and deleting DPN's {}.", schemaName, lstDpnsForAdd,
357                 lstDpnsForDelete);
358
359         VtepConfigSchema schema = ItmUtils.validateForUpdateVtepSchema(schemaName, lstDpnsForAdd, lstDpnsForDelete,
360                 this);
361         VtepConfigSchemaBuilder builder = new VtepConfigSchemaBuilder(schema);
362        /* if (ItmUtils.getDpnIdList(schema.getDpnIds()).isEmpty()) {
363             builder.setDpnIds(schema.getDpnIds());
364         } else {*/
365         if (lstDpnsForAdd != null && !lstDpnsForAdd.isEmpty()) {
366             List<BigInteger> originalDpnList = ItmUtils.getDpnIdList(nullToEmpty(schema.getDpnIds()));
367             originalDpnList.addAll(lstDpnsForAdd) ;
368             builder.setDpnIds(ItmUtils.getDpnIdsListFromBigInt(originalDpnList));
369         }
370         if (lstDpnsForDelete != null && !lstDpnsForDelete.isEmpty()) {
371             List<BigInteger> originalDpnList = ItmUtils.getDpnIdList(nullToEmpty(schema.getDpnIds()));
372             originalDpnList.removeAll(lstDpnsForDelete) ;
373             builder.setDpnIds(ItmUtils.getDpnIdsListFromBigInt(originalDpnList));
374             // schema.setDpnIds(ItmUtils.getDpnIdsListFromBigInt(ItmUtils.getDpnIdList(schema.getDpnIds())
375             // .removeAll(lstDpnsForAdd)));
376         }
377         // }
378         schema = builder.build();
379         MDSALUtil.syncWrite(this.dataBroker, LogicalDatastoreType.CONFIGURATION,
380                 ItmUtils.getVtepConfigSchemaIdentifier(schemaName), schema);
381         LOG.debug("Vtep config schema {} updated to config DS with DPN's {}",
382                 schemaName, ItmUtils.getDpnIdList(schema.getDpnIds()));
383     }
384
385     @Override
386     public void deleteAllVtepSchemas() {
387         List<VtepConfigSchema> lstSchemas = getAllVtepConfigSchemas();
388         if (lstSchemas != null && !lstSchemas.isEmpty()) {
389             for (VtepConfigSchema schema : lstSchemas) {
390                 MDSALUtil.syncDelete(this.dataBroker, LogicalDatastoreType.CONFIGURATION,
391                         ItmUtils.getVtepConfigSchemaIdentifier(schema.getSchemaName()));
392             }
393         }
394         LOG.debug("Deleted all Vtep schemas from config DS");
395     }
396
397     @Override
398     public void configureTunnelMonitorParams(boolean monitorEnabled, String monitorProtocol) {
399         tepCommandHelper.configureTunnelMonitorParams(monitorEnabled, monitorProtocol);
400     }
401
402     @Override
403     public void configureTunnelMonitorInterval(int interval) {
404         tepCommandHelper.configureTunnelMonitorInterval(interval);
405     }
406
407     @Override
408     public boolean validateIP(final String ip) {
409         if (ip == null || ip.isEmpty() || "null".equals(ip) || "0.0.0.0".equals(ip)) {
410             return false;
411         }
412         final String PTRN =
413                 "^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
414         Pattern pattern = Pattern.compile(PTRN);
415         Matcher matcher = pattern.matcher(ip);
416         return matcher.matches();
417     }
418
419     @Override
420     public Interface getInterface(String tunnelName) {
421         return dpnTepStateCache.getInterfaceFromCache(tunnelName);
422     }
423
424     @Override
425     public Optional<StateTunnelList> getTunnelState(String interfaceName) throws ReadFailedException {
426         return tunnelStateCache.get(tunnelStateCache.getStateTunnelListIdentifier(interfaceName));
427     }
428 }