Convert itm-impl to use mdsal-binding-util
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / recovery / impl / ItmTzInstanceRecoveryHandler.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 static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
11
12 import java.time.Duration;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.concurrent.atomic.AtomicInteger;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
23 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
24 import org.opendaylight.genius.itm.cache.DpnTepStateCache;
25 import org.opendaylight.genius.itm.globals.ITMConstants;
26 import org.opendaylight.genius.itm.impl.ItmUtils;
27 import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
28 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
29 import org.opendaylight.mdsal.binding.api.DataBroker;
30 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
31 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
32 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
33 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
34 import org.opendaylight.serviceutils.srm.ServiceRecoveryInterface;
35 import org.opendaylight.serviceutils.srm.ServiceRecoveryRegistry;
36 import org.opendaylight.serviceutils.tools.listener.AbstractSyncDataTreeChangeListener;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.DpnsTeps;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.dpns.teps.RemoteDpns;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.dpns.teps.RemoteDpnsKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelListKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZone;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.serviceutils.srm.types.rev180626.GeniusItmTz;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
46 import org.opendaylight.yangtools.yang.common.Uint64;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 @Singleton
51 public class ItmTzInstanceRecoveryHandler extends
52         AbstractSyncDataTreeChangeListener<StateTunnelList> implements ServiceRecoveryInterface {
53
54     private static final Logger LOG = LoggerFactory.getLogger(ItmTzInstanceRecoveryHandler.class);
55
56     private final JobCoordinator jobCoordinator;
57     private final DataBroker dataBroker;
58     private final ManagedNewTransactionRunner txRunner;
59     private final EntityOwnershipUtils entityOwnershipUtils;
60     private final DataTreeEventCallbackRegistrar eventCallbacks;
61     private final EntityOwnershipService entityOwnershipService;
62     private final IInterfaceManager interfaceManager;
63     private final DpnTepStateCache dpnTepStateCache;
64
65     @Inject
66     public ItmTzInstanceRecoveryHandler(DataBroker dataBroker,
67                                         JobCoordinator jobCoordinator,
68                                         ServiceRecoveryRegistry serviceRecoveryRegistry,
69                                         EntityOwnershipUtils entityOwnershipUtils,
70                                         EntityOwnershipService entityOwnershipService,
71                                         DataTreeEventCallbackRegistrar eventCallbacks,
72                                         IInterfaceManager interfaceManager,
73                                         DpnTepStateCache dpnTepStateCache) {
74         super(dataBroker, LogicalDatastoreType.OPERATIONAL,
75                 InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class));
76         this.dataBroker = dataBroker;
77         this.jobCoordinator = jobCoordinator;
78         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
79         this.entityOwnershipUtils = entityOwnershipUtils;
80         this.entityOwnershipService = entityOwnershipService;
81         serviceRecoveryRegistry.registerServiceRecoveryRegistry(getServiceRegistryKey(), this);
82         this.eventCallbacks = eventCallbacks;
83         this.interfaceManager = interfaceManager;
84         this.dpnTepStateCache = dpnTepStateCache;
85
86     }
87
88     private String getServiceRegistryKey() {
89         return GeniusItmTz.class.toString();
90     }
91
92     @Override
93     public void recoverService(String entityId) {
94         if (!entityOwnershipUtils.isEntityOwner(ITMConstants.ITM_CONFIG_ENTITY, ITMConstants.ITM_CONFIG_ENTITY)) {
95             return;
96         }
97         LOG.info("Trigerred recovery of ITM Instance - TZ Name {}", entityId);
98         try {
99             recoverTransportZone(entityId);
100         } catch (InterruptedException e) {
101             LOG.error("ITM instance transportzone has not recovered", e);
102         }
103     }
104
105     private void recoverTransportZone(String entityId) throws InterruptedException {
106         //List of Internel tunnels
107         List<String> tunnelList = new ArrayList<>();
108         if (interfaceManager.isItmDirectTunnelsEnabled()) {
109             Collection<DpnsTeps> dpnsTeps = dpnTepStateCache.getAllPresent();
110             List<Uint64> listOfDpnIds = ItmUtils.getDpIdFromTransportzone(dataBroker, entityId);
111             for (DpnsTeps dpnTep : dpnsTeps) {
112                 @Nullable Map<RemoteDpnsKey, RemoteDpns> rmtdpns = dpnTep.getRemoteDpns();
113                 for (RemoteDpns remoteDpn : rmtdpns.values()) {
114                     if (listOfDpnIds.contains(remoteDpn.getDestinationDpnId())) {
115                         tunnelList.add(remoteDpn.getTunnelName());
116                     }
117                 }
118             }
119             LOG.trace("List of tunnels to be recovered : {}", tunnelList);
120         } else {
121             //List of Internal tunnels
122             tunnelList.addAll(ItmUtils.getInternalTunnelInterfaces(dataBroker));
123         }
124         LOG.debug("List of tunnel interfaces: {}" , tunnelList);
125         InstanceIdentifier<TransportZone> tzII = ItmUtils.getTZInstanceIdentifier(entityId);
126         TransportZone tz = ItmUtils.getTransportZoneFromConfigDS(entityId , dataBroker);
127         if (tz != null) {
128             LOG.trace("deleting transportzone instance {}", entityId);
129             jobCoordinator.enqueueJob(entityId, () -> Collections.singletonList(
130                 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> tx.delete(tzII))),
131                 ITMConstants.JOB_MAX_RETRIES);
132             AtomicInteger eventCallbackCount = new AtomicInteger(0);
133             if (!tunnelList.isEmpty()) {
134                 tunnelList.forEach(tunnelInterface -> {
135                     StateTunnelListKey tlKey = new StateTunnelListKey(tunnelInterface);
136                     LOG.trace("TunnelStateKey: {} for interface: {}", tlKey, tunnelInterface);
137                     InstanceIdentifier<StateTunnelList> stListId = ItmUtils.buildStateTunnelListId(tlKey);
138                     eventCallbacks.onRemove(LogicalDatastoreType.OPERATIONAL, stListId, (unused) -> {
139                         LOG.trace("on removal of {}, event callback triggered", stListId);
140                         // recreating the transportZone
141                         recreateTZ(entityId, tz, tzII, tunnelList.size(), eventCallbackCount);
142                         return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
143                     }, Duration.ofMillis(5000), (id) -> {
144                             LOG.trace("event callback timed out for {} tunnel interface ", tunnelInterface);
145                             recreateTZ(entityId, tz, tzII, tunnelList.size(), eventCallbackCount); });
146                 });
147             } else {
148                 LOG.trace("List of tunnels to be recovered is empty, still recreate transportzone {}",entityId);
149                 recreateTZ(entityId, tz, tzII, tunnelList.size(), eventCallbackCount);
150             }
151         }
152     }
153
154     //this function will recreate the transportzone instance
155     private void recreateTZ(String entityId, TransportZone tz, InstanceIdentifier<TransportZone> tzII,
156                             int sizeOfTunnelList, AtomicInteger registeredEvents) {
157         registeredEvents.incrementAndGet();
158         if (registeredEvents.intValue() == sizeOfTunnelList || sizeOfTunnelList == 0) {
159             LOG.trace("recreating transportzone instance {}", entityId);
160             jobCoordinator.enqueueJob(entityId, () -> Collections.singletonList(
161                 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> tx.merge(tzII, tz))),
162                 ITMConstants.JOB_MAX_RETRIES);
163         }
164     }
165 }