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