Drop nullToEmpty
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / recovery / impl / ItmTepInstanceRecoveryHandler.java
1 /*
2  * Copyright (c) 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.recovery.impl;
9
10 import java.time.Duration;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.Objects;
14 import java.util.concurrent.atomic.AtomicInteger;
15 import javax.inject.Inject;
16 import javax.inject.Singleton;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
20 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
21 import org.opendaylight.genius.itm.cache.DPNTEPsInfoCache;
22 import org.opendaylight.genius.itm.cache.DpnTepStateCache;
23 import org.opendaylight.genius.itm.cache.OvsBridgeEntryCache;
24 import org.opendaylight.genius.itm.cache.OvsBridgeRefEntryCache;
25 import org.opendaylight.genius.itm.cache.TunnelStateCache;
26 import org.opendaylight.genius.itm.confighelpers.ItmExternalTunnelAddWorker;
27 import org.opendaylight.genius.itm.confighelpers.ItmInternalTunnelAddWorker;
28 import org.opendaylight.genius.itm.confighelpers.ItmInternalTunnelDeleteWorker;
29 import org.opendaylight.genius.itm.confighelpers.ItmTepAddWorker;
30 import org.opendaylight.genius.itm.confighelpers.ItmTepRemoveWorker;
31 import org.opendaylight.genius.itm.globals.ITMConstants;
32 import org.opendaylight.genius.itm.impl.ItmUtils;
33 import org.opendaylight.genius.itm.impl.TunnelMonitoringConfig;
34 import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
35 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
36 import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
37 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
38 import org.opendaylight.serviceutils.srm.ServiceRecoveryInterface;
39 import org.opendaylight.serviceutils.srm.ServiceRecoveryRegistry;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.ItmConfig;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.tunnel.end.points.TzMembership;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnel;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelListKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZone;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.Subnets;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.Vteps;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.serviceutils.srm.types.rev180626.GeniusItmTep;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 @Singleton
57 public class ItmTepInstanceRecoveryHandler implements ServiceRecoveryInterface {
58
59     private static final Logger LOG = LoggerFactory.getLogger(ItmTepInstanceRecoveryHandler.class);
60
61     private final JobCoordinator jobCoordinator;
62     private final ItmInternalTunnelAddWorker itmInternalTunnelAddWorker;
63     private final ItmExternalTunnelAddWorker itmExternalTunnelAddWorker;
64     private final DPNTEPsInfoCache dpntePsInfoCache;
65     private final DataBroker dataBroker;
66     private final ItmInternalTunnelDeleteWorker itmInternalTunnelDeleteWorker;
67     private final ItmConfig itmConfig;
68     private final EntityOwnershipUtils entityOwnershipUtils;
69     private final IMdsalApiManager imdsalApiManager;
70     private final DataTreeEventCallbackRegistrar eventCallbacks;
71
72     @Inject
73     public ItmTepInstanceRecoveryHandler(DataBroker dataBroker,
74                                          ItmConfig itmConfig,
75                                          IMdsalApiManager imdsalApiMgr,
76                                          JobCoordinator jobCoordinator,
77                                          TunnelMonitoringConfig tunnelMonitoringConfig,
78                                          DPNTEPsInfoCache dpntePsInfoCache, TunnelStateCache tunnelStateCache,
79                                          DirectTunnelUtils directTunnelUtils, DpnTepStateCache dpnTepStateCache,
80                                          OvsBridgeEntryCache ovsBridgeEntryCache,
81                                          OvsBridgeRefEntryCache ovsBridgeRefEntryCache,
82                                          IInterfaceManager interfaceManager,
83                                          ServiceRecoveryRegistry serviceRecoveryRegistry,
84                                          EntityOwnershipUtils entityOwnershipUtils,
85                                          DataTreeEventCallbackRegistrar eventCallbacks) {
86         this.dataBroker = dataBroker;
87         this.itmConfig = itmConfig;
88         this.imdsalApiManager = imdsalApiMgr;
89         this.jobCoordinator = jobCoordinator;
90         this.dpntePsInfoCache = dpntePsInfoCache;
91         this.entityOwnershipUtils = entityOwnershipUtils;
92         this.eventCallbacks = eventCallbacks;
93         this.itmInternalTunnelAddWorker = new ItmInternalTunnelAddWorker(dataBroker, jobCoordinator,
94                 tunnelMonitoringConfig, itmConfig, directTunnelUtils, interfaceManager, ovsBridgeRefEntryCache);
95         this.itmExternalTunnelAddWorker = new ItmExternalTunnelAddWorker(dataBroker, itmConfig,
96                 dpntePsInfoCache);
97         this.itmInternalTunnelDeleteWorker = new ItmInternalTunnelDeleteWorker(dataBroker, jobCoordinator,
98                 tunnelMonitoringConfig, interfaceManager, dpnTepStateCache, ovsBridgeEntryCache,
99                 ovsBridgeRefEntryCache, tunnelStateCache,
100                 directTunnelUtils);
101         serviceRecoveryRegistry.registerServiceRecoveryRegistry(getServiceRegistryKey(), this);
102     }
103
104     private String getServiceRegistryKey() {
105         return GeniusItmTep.class.toString();
106     }
107
108     @Override
109     public void recoverService(String entityId) {
110         if (!entityOwnershipUtils.isEntityOwner(ITMConstants.ITM_CONFIG_ENTITY, ITMConstants.ITM_CONFIG_ENTITY)) {
111             return;
112         }
113         LOG.info("Trigerred recovery of ITM Instance - Tep {}", entityId);
114         try {
115             recoverTep(entityId);
116         } catch (InterruptedException e) {
117             LOG.error("ITM Instance tep has not been recovered.", e);
118         }
119     }
120
121     private void recoverTep(String entityId) throws InterruptedException {
122         List<DPNTEPsInfo> tepsToRecover = new ArrayList<>();
123         String[] params = entityId.split(":");
124         if (params.length < 2) {
125             LOG.error("Not enough arguments..Exiting...");
126         } else if (params.length > 2) {
127             LOG.info("Ignoring extra parameter and proceeding...");
128         }
129         String tzName = params[0];
130         String ipAddress = params[1];
131         TransportZone oldTz = ItmUtils.getTransportZoneFromConfigDS(tzName, dataBroker);
132         DPNTEPsInfo dpnTepsToRecover = extractDPNTepsInfo(tzName, ipAddress, oldTz);
133         if (dpnTepsToRecover == null) {
134             LOG.error("Please Enter appropriate arguments for Tep Recovery.");
135             return;
136         } else {
137             tepsToRecover.add(dpnTepsToRecover);
138             //List of Internel tunnels
139             List<InternalTunnel> tunnelList = ItmUtils.getInternalTunnelsFromCache(dataBroker);
140             List<String> interfaceListToRecover = new ArrayList<>();
141             LOG.debug("List of tunnel interfaces: {}" , tunnelList);
142
143             if (oldTz != null) {
144                 LOG.trace("Deleting transportzone {}", tzName);
145                 ItmTepRemoveWorker tepRemoveWorker = new ItmTepRemoveWorker(tepsToRecover, null, oldTz,
146                         dataBroker, imdsalApiManager, itmInternalTunnelDeleteWorker, dpntePsInfoCache);
147                 jobCoordinator.enqueueJob(tzName, tepRemoveWorker);
148                 AtomicInteger eventCallbackCount = new AtomicInteger(0);
149                 AtomicInteger eventRegistrationCount = new AtomicInteger(0);
150                 tunnelList.stream().filter(internalTunnel -> Objects.equals(internalTunnel
151                         .getDestinationDPN(), dpnTepsToRecover.getDPNID()) || Objects.equals(
152                         internalTunnel.getSourceDPN(), dpnTepsToRecover.getDPNID())).forEach(internalTunnel -> {
153                             eventRegistrationCount.incrementAndGet();
154                             interfaceListToRecover.add(String.valueOf(internalTunnel.getTunnelInterfaceNames())); });
155
156                 if (!interfaceListToRecover.isEmpty()) {
157                     interfaceListToRecover.forEach(interfaceName -> {
158                         StateTunnelListKey tlKey = new StateTunnelListKey(interfaceName);
159                         LOG.trace("TunnelStateKey: {} for interface: {}", tlKey, interfaceName);
160                         InstanceIdentifier<StateTunnelList> stListId = ItmUtils.buildStateTunnelListId(tlKey);
161                         eventCallbacks.onRemove(LogicalDatastoreType.OPERATIONAL, stListId, (unused) -> {
162                             LOG.trace("callback event for a delete {} interface instance....", stListId);
163                             // recreating the transportZone
164                             recreateTEP(tzName, tepsToRecover, eventCallbackCount, interfaceListToRecover.size());
165                             return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
166                         }, Duration.ofMillis(5000), (id) -> {
167                                 LOG.trace("event callback timed out for {} tunnel interface ", interfaceName);
168                                 recreateTEP(tzName, tepsToRecover, eventCallbackCount, interfaceListToRecover.size());
169                             });
170                     });
171                 } else {
172                     recreateTEP(tzName, tepsToRecover, eventCallbackCount, interfaceListToRecover.size());
173                 }
174             }
175         }
176     }
177
178
179     private void recreateTEP(String tzName, List tepts, AtomicInteger eventCallbackCount, int registeredEventSize) {
180         eventCallbackCount.incrementAndGet();
181         if (eventCallbackCount.intValue() == registeredEventSize || registeredEventSize == 0) {
182             LOG.info("Re-creating TEP {}", tzName);
183             ItmTepAddWorker tepAddWorker = new ItmTepAddWorker(tepts, null, dataBroker,
184                     imdsalApiManager, itmConfig, itmInternalTunnelAddWorker, itmExternalTunnelAddWorker,
185                     dpntePsInfoCache);
186             jobCoordinator.enqueueJob(tzName, tepAddWorker);
187         } else {
188             LOG.trace("{} call back events registered for {} tunnel interfaces",
189                     registeredEventSize, eventCallbackCount);
190         }
191     }
192
193     private DPNTEPsInfo extractDPNTepsInfo(String tzName, String ipAddress, TransportZone transportZone) {
194
195         if (transportZone == null) {
196             LOG.error("Transportzone name {} is not valid.", tzName);
197             return null;
198         }
199
200         for (Subnets sub : transportZone.nonnullSubnets()) {
201             if (sub.getVteps() == null || sub.getVteps().isEmpty()) {
202                 LOG.error("Transport Zone {} subnet {} has no vteps", transportZone.getZoneName(), sub.getPrefix());
203             }
204             for (Vteps vtep : sub.getVteps()) {
205                 if (ipAddress.equals(vtep.getIpAddress().stringValue())) {
206
207                     List<TzMembership> zones = ItmUtils.createTransportZoneMembership(tzName);
208                     LOG.trace("Transportzone {} found match for tep {} to be recovered", transportZone.getZoneName(),
209                             ipAddress);
210
211                     //OfTunnels is false byDefault
212                     TunnelEndPoints tunnelEndPoints = ItmUtils.createTunnelEndPoints(vtep.getDpnId(),
213                         IpAddressBuilder.getDefaultInstance(ipAddress), vtep.getPortname(), false, sub.getVlanId(),
214                             sub.getPrefix(), sub.getGatewayIp(), zones,transportZone.getTunnelType(),
215                             itmConfig.getDefaultTunnelTos());
216
217                     List<TunnelEndPoints> teps = new ArrayList<>();
218                     teps.add(tunnelEndPoints);
219                     return ItmUtils.createDPNTepInfo(vtep.getDpnId(), teps);
220                 }
221             }
222         }
223         return null;
224     }
225 }