Exception Handling in UpgradeStateListener
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / UpgradeStateListener.java
1 /*
2  * Copyright (c) 2017 Red Hat, Inc. 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
9 package org.opendaylight.netvirt.natservice.internal;
10
11 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12
13 import com.google.common.base.Optional;
14
15 import java.math.BigInteger;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.concurrent.ExecutionException;
19
20 import javax.annotation.Nonnull;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
23
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
28 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
29 import org.opendaylight.genius.infra.Datastore.Configuration;
30 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
31 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
32 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
33 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
34 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
35 import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
36 import org.opendaylight.serviceutils.tools.mdsal.listener.AbstractClusteredSyncDataTreeChangeListener;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsalutil.rev170830.Config;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51 @Singleton
52 public class UpgradeStateListener extends AbstractClusteredSyncDataTreeChangeListener<Config> {
53     private static final Logger LOG = LoggerFactory.getLogger(UpgradeStateListener.class);
54
55     private final DataBroker dataBroker;
56     private final CentralizedSwitchScheduler centralizedSwitchScheduler;
57     private final NatserviceConfig.NatMode natMode;
58     private SNATDefaultRouteProgrammer defaultRouteProgrammer;
59     private IMdsalApiManager mdsalManager;
60     private IdManagerService idManager;
61     private NaptSwitchHA naptSwitchHA;
62     private final JobCoordinator coordinator;
63     private final ManagedNewTransactionRunner txRunner;
64
65     @Inject
66     public UpgradeStateListener(final DataBroker dataBroker,
67                                 final CentralizedSwitchScheduler centralizedSwitchScheduler,
68                                 final SNATDefaultRouteProgrammer defaultRouteProgrammer,
69                                 final IMdsalApiManager mdsalManager,
70                                 final IdManagerService idManager,
71                                 final NaptSwitchHA naptSwitchHA,
72                                 final NatserviceConfig config, final JobCoordinator coordinator) {
73         super(dataBroker, new DataTreeIdentifier<>(
74                 LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Config.class)));
75         this.dataBroker = dataBroker;
76         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
77         this.centralizedSwitchScheduler = centralizedSwitchScheduler;
78         this.defaultRouteProgrammer = defaultRouteProgrammer;
79         this.coordinator = coordinator;
80         this.naptSwitchHA = naptSwitchHA;
81         if (config != null) {
82             this.natMode = config.getNatMode();
83         } else {
84             this.natMode = NatserviceConfig.NatMode.Controller;
85         }
86         LOG.trace("UpgradeStateListener (nat) initialized");
87     }
88
89     @Override
90     public void add(@Nonnull Config newDataObject) {
91     }
92
93     @Override
94     public void remove(@Nonnull Config removedDataObject) {
95         if (natMode == NatserviceConfig.NatMode.Conntrack) {
96             return;
97         }
98         LOG.debug("Verify is all Elected Napt Switch and connected back post upgrade");
99     }
100
101     @Override
102     public void update(@Nonnull Config original, Config updated) {
103         if (natMode == NatserviceConfig.NatMode.Controller) {
104             if (original.isUpgradeInProgress() && !updated.isUpgradeInProgress()) {
105                 Optional<NaptSwitches> npatSwitches = NatUtil.getAllPrimaryNaptSwitches(dataBroker);
106                 if (npatSwitches.isPresent()) {
107                     for (RouterToNaptSwitch routerToNaptSwitch : npatSwitches.get().getRouterToNaptSwitch()) {
108                         BigInteger primaryNaptDpnId = routerToNaptSwitch.getPrimarySwitchId();
109                         if (!NatUtil.getSwitchStatus(dataBroker, routerToNaptSwitch.getPrimarySwitchId())) {
110                             String routerUuid = routerToNaptSwitch.getRouterName();
111                             coordinator.enqueueJob((NatConstants.NAT_DJC_PREFIX + routerUuid),
112                                 () -> Collections.singletonList(
113                                     txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
114                                         reElectNewNaptSwitch(routerUuid, primaryNaptDpnId, confTx);
115                                     }
116                                 )), NatConstants.NAT_DJC_MAX_RETRIES);
117                         }
118                     }
119                 }
120             }
121             return;
122         }
123
124         LOG.info("UpgradeStateListener update from {} to {}", original, updated);
125         if (!(original.isUpgradeInProgress() && !updated.isUpgradeInProgress())) {
126             return;
127         }
128
129         SingleTransactionDataBroker reader = new SingleTransactionDataBroker(dataBroker);
130         ExtRouters routers;
131         try {
132             routers = reader.syncRead(LogicalDatastoreType.CONFIGURATION,
133                     InstanceIdentifier.create(ExtRouters.class));
134         } catch (ReadFailedException e) {
135             LOG.error("Error reading external routers", e);
136             return;
137         }
138
139         for (Routers router : routers.getRouters()) {
140             List<ExternalIps> externalIps = router.getExternalIps();
141             if (router.isEnableSnat() && externalIps != null && !externalIps.isEmpty()) {
142                 centralizedSwitchScheduler.scheduleCentralizedSwitch(router);
143             }
144         }
145     }
146
147     private void reElectNewNaptSwitch(String routerName, BigInteger primaryNaptDpnId,
148             TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
149         // Check if this is externalRouter else ignore
150         InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
151         Optional<Routers> routerData =
152                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
153                         LogicalDatastoreType.CONFIGURATION, extRoutersId);
154         if (!routerData.isPresent()) {
155             LOG.debug("reElectNewNaptSwitch : SNAT->Ignoring Re-election for router {} since its not External Router",
156                     routerName);
157             return;
158         }
159         Uuid networkId = routerData.get().getNetworkId();
160         if (networkId == null) {
161             LOG.error("hndlTepDelForSnatInEachRtr : SNAT -> Ignoring Re-election  with Napt {} for router {}"
162                     + "as external network configuraton is missing", primaryNaptDpnId, routerName);
163             return;
164         }
165         long routerId = NatUtil.getVpnId(dataBroker, routerName);
166         LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Router {} is associated with ext nw {}", routerId, networkId);
167         Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
168         Long bgpVpnId;
169         if (bgpVpnUuid == null) {
170             LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Internal VPN-ID {} associated to router {}",
171                     routerId, routerName);
172             bgpVpnId = routerId;
173         } else {
174             bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
175             if (bgpVpnId == NatConstants.INVALID_ID) {
176                 LOG.error("hndlTepDelForSnatInEachRtr :SNAT->Invalid Private BGP VPN ID returned for routerName {}",
177                         routerName);
178                 return;
179             }
180         }
181         defaultRouteProgrammer.removeDefNATRouteInDPN(primaryNaptDpnId, bgpVpnId, confTx);
182         if (routerData.get().isEnableSnat()) {
183             LOG.info("hndlTepDelForSnatInEachRtr : SNAT enabled for router {}", routerId);
184
185             long routerVpnId = routerId;
186             if (bgpVpnId != NatConstants.INVALID_ID) {
187                 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} "
188                         + "associated to the router {}", bgpVpnId, routerName);
189                 routerVpnId = bgpVpnId;
190             } else {
191                 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Internal L3 VPN ID (Router ID) {} "
192                         + "associated to the router {}", routerVpnId, routerName);
193             }
194             //Re-elect the other available switch as the NAPT switch and program the NAT flows.
195             ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
196                     routerName, networkId);
197             if (extNwProvType == null) {
198                 return;
199             }
200             NatUtil.removeSNATFromDPN(dataBroker, mdsalManager, idManager, naptSwitchHA, primaryNaptDpnId, routerName,
201                     routerId, routerVpnId, extNwProvType, confTx);
202
203         } else {
204             LOG.info("hndlTepDelForSnatInEachRtr : SNAT is not enabled for router {} to handle addDPN event {}",
205                     routerId, primaryNaptDpnId);
206         }
207     }
208
209 }