Migrate ListenableFutures.addErrorLogging() callers
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / commons / AlivenessMonitorUtils.java
1 /*
2  * Copyright (c) 2016, 2017 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.interfacemanager.commons;
9
10 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
11
12 import com.google.common.util.concurrent.ListenableFuture;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Objects;
16 import java.util.Optional;
17 import java.util.concurrent.ExecutionException;
18 import java.util.concurrent.Future;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21 import org.apache.aries.blueprint.annotation.service.Reference;
22 import org.opendaylight.genius.infra.Datastore.Operational;
23 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
24 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
25 import org.opendaylight.genius.infra.TypedReadTransaction;
26 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
27 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
28 import org.opendaylight.mdsal.binding.api.DataBroker;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.AlivenessMonitorService;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileCreateInput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileCreateInputBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileCreateOutput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileDeleteInput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileDeleteInputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileDeleteOutput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileGetInput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileGetInputBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProfileGetOutput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorProtocolType;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStartInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStartInputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStartOutput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStopInput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStopInputBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitorStopOutput;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.MonitoringMode;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.params.SourceBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profile.create.input.Profile;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.profile.create.input.ProfileBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor.rev160411.monitor.start.input.ConfigBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.InterfaceMonitorIdMap;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.MonitorIdInterfaceMap;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.monitor.id.map.InterfaceMonitorId;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.monitor.id.map.InterfaceMonitorIdBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.monitor.id.map.InterfaceMonitorIdKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.monitor.id._interface.map.MonitorIdInterface;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.monitor.id._interface.map.MonitorIdInterfaceBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.monitor.id._interface.map.MonitorIdInterfaceKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeLldp;
62 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
63 import org.opendaylight.yangtools.yang.common.RpcResult;
64 import org.opendaylight.yangtools.yang.common.Uint32;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67
68 @Singleton
69 public final class AlivenessMonitorUtils {
70
71     private static final Logger LOG = LoggerFactory.getLogger(AlivenessMonitorUtils.class);
72     private static final long FAILURE_THRESHOLD = 4;
73     private static final long MONITORING_WINDOW = 4;
74
75     private final AlivenessMonitorService alivenessMonitorService;
76     private final ManagedNewTransactionRunner txRunner;
77
78     @Inject
79     public AlivenessMonitorUtils(AlivenessMonitorService alivenessMonitor, @Reference DataBroker dataBroker) {
80         this.alivenessMonitorService = alivenessMonitor;
81         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
82     }
83
84     public void startLLDPMonitoring(IfTunnel ifTunnel, String trunkInterfaceName) {
85         // LLDP monitoring for the tunnel interface
86         if (lldpMonitoringEnabled(ifTunnel)) {
87             MonitorStartInput lldpMonitorInput = new MonitorStartInputBuilder()
88                     .setConfig(new ConfigBuilder()
89                             .setSource(new SourceBuilder()
90                                     .setEndpointType(
91                                             getInterfaceForMonitoring(trunkInterfaceName, ifTunnel.getTunnelSource()))
92                                     .build())
93                             .setMode(MonitoringMode.OneOne)
94                             .setProfileId(allocateProfile(FAILURE_THRESHOLD,
95                                     ifTunnel.getMonitorInterval().toJava(), MONITORING_WINDOW,
96                                     MonitorProtocolType.Lldp))
97                             .build())
98                     .build();
99             try {
100                 Future<RpcResult<MonitorStartOutput>> result = alivenessMonitorService.monitorStart(lldpMonitorInput);
101                 RpcResult<MonitorStartOutput> rpcResult = result.get();
102                 if (rpcResult.isSuccessful()) {
103                     long monitorId = rpcResult.getResult().getMonitorId().toJava();
104                     LoggingFutures.addErrorLogging(
105                         txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
106                             createOrUpdateInterfaceMonitorIdMap(tx, trunkInterfaceName, monitorId);
107                             createOrUpdateMonitorIdInterfaceMap(tx, trunkInterfaceName, monitorId);
108                             LOG.trace("Started LLDP monitoring with id {}", monitorId);
109                         }), LOG, "Error starting monitoring");
110                 } else {
111                     LOG.warn("RPC Call to start monitoring returned with Errors {}", rpcResult.getErrors());
112                 }
113             } catch (InterruptedException | ExecutionException e) {
114                 LOG.warn("Exception when starting monitoring", e);
115             }
116         }
117     }
118
119     public void stopLLDPMonitoring(IfTunnel ifTunnel, String trunkInterface) {
120         if (!lldpMonitoringEnabled(ifTunnel)) {
121             return;
122         }
123         LOG.debug("stop LLDP monitoring for {}", trunkInterface);
124         LoggingFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
125             List<Uint32> monitorIds = getMonitorIdForInterface(tx, trunkInterface);
126             if (monitorIds == null) {
127                 LOG.error("Monitor Id doesn't exist for Interface {}", trunkInterface);
128                 return;
129             }
130             for (Uint32 monitorId : monitorIds) {
131                 String interfaceName = getInterfaceFromMonitorId(tx, monitorId);
132                 if (interfaceName != null) {
133                     MonitorStopInput input = new MonitorStopInputBuilder().setMonitorId(monitorId).build();
134
135                     ListenableFuture<RpcResult<MonitorStopOutput>> future = alivenessMonitorService.monitorStop(input);
136                     LoggingFutures.addErrorLogging(future, LOG, "Stop LLDP monitoring for {}", trunkInterface);
137
138                     removeMonitorIdInterfaceMap(tx, monitorId);
139                     removeMonitorIdFromInterfaceMonitorIdMap(tx, interfaceName, monitorId);
140                     return;
141                 }
142             }
143         }), LOG, "Error stopping LLDP monitoring for {}", trunkInterface);
144     }
145
146     public static String getInterfaceFromMonitorId(TypedReadTransaction<Operational> tx, Uint32 monitorId)
147         throws ExecutionException, InterruptedException {
148         InstanceIdentifier<MonitorIdInterface> id = InstanceIdentifier.builder(MonitorIdInterfaceMap.class)
149                 .child(MonitorIdInterface.class, new MonitorIdInterfaceKey(monitorId)).build();
150         return tx.read(id).get().map(MonitorIdInterface::getInterfaceName).orElse(null);
151     }
152
153     private void removeMonitorIdInterfaceMap(TypedReadWriteTransaction<Operational> tx, Uint32 monitorId)
154         throws ExecutionException, InterruptedException {
155         InstanceIdentifier<MonitorIdInterface> id = InstanceIdentifier.builder(MonitorIdInterfaceMap.class)
156                 .child(MonitorIdInterface.class, new MonitorIdInterfaceKey(monitorId)).build();
157         if (tx.read(id).get().isPresent()) {
158             tx.delete(id);
159         }
160     }
161
162     private void removeMonitorIdFromInterfaceMonitorIdMap(TypedReadWriteTransaction<Operational> tx, String infName,
163         Uint32 monitorId) throws ExecutionException, InterruptedException {
164         InstanceIdentifier<InterfaceMonitorId> id = InstanceIdentifier.builder(InterfaceMonitorIdMap.class)
165                 .child(InterfaceMonitorId.class, new InterfaceMonitorIdKey(infName)).build();
166         Optional<InterfaceMonitorId> interfaceMonitorIdMap = tx.read(id).get();
167         if (interfaceMonitorIdMap.isPresent()) {
168             InterfaceMonitorId interfaceMonitorIdInstance = interfaceMonitorIdMap.get();
169             List<Uint32> existingMonitorIds = interfaceMonitorIdInstance.getMonitorId();
170             if (existingMonitorIds != null && existingMonitorIds.contains(monitorId)) {
171                 existingMonitorIds.remove(monitorId);
172                 InterfaceMonitorIdBuilder interfaceMonitorIdBuilder = new InterfaceMonitorIdBuilder();
173                 interfaceMonitorIdInstance = interfaceMonitorIdBuilder.withKey(new InterfaceMonitorIdKey(infName))
174                         .setMonitorId(existingMonitorIds).build();
175                 tx.mergeParentStructureMerge(id, interfaceMonitorIdInstance);
176             }
177         }
178     }
179
180     private static org.opendaylight.yang.gen.v1
181         .urn.opendaylight.genius.alivenessmonitor
182         .rev160411.endpoint.endpoint.type.Interface getInterfaceForMonitoring(
183             String interfaceName,
184             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress ipAddress) {
185         return new org.opendaylight.yang.gen.v1.urn.opendaylight
186                 .genius.alivenessmonitor.rev160411.endpoint.endpoint.type.InterfaceBuilder()
187                 .setInterfaceIp(ipAddress).setInterfaceName(interfaceName).build();
188     }
189
190     public void handleTunnelMonitorUpdates(Interface interfaceOld, Interface interfaceNew) {
191         String interfaceName = interfaceNew.getName();
192         IfTunnel ifTunnelNew = interfaceNew.augmentation(IfTunnel.class);
193         if (!lldpMonitoringEnabled(ifTunnelNew)) {
194             return;
195         }
196         LOG.debug("handling tunnel monitoring updates for interface {}", interfaceName);
197
198         stopLLDPMonitoring(ifTunnelNew, interfaceOld.getName());
199         if (ifTunnelNew.isMonitorEnabled()) {
200             startLLDPMonitoring(ifTunnelNew, interfaceName);
201
202             // Delete old profile from Aliveness Manager
203             IfTunnel ifTunnelOld = interfaceOld.augmentation(IfTunnel.class);
204             if (!Objects.equals(ifTunnelNew.getMonitorInterval(), ifTunnelOld.getMonitorInterval())) {
205                 LOG.debug("deleting older monitor profile for interface {}", interfaceName);
206                 Uint32 profileId = allocateProfile(FAILURE_THRESHOLD, ifTunnelOld.getMonitorInterval().toJava(),
207                         MONITORING_WINDOW, MonitorProtocolType.Lldp);
208                 MonitorProfileDeleteInput profileDeleteInput = new MonitorProfileDeleteInputBuilder()
209                         .setProfileId(profileId).build();
210
211                 ListenableFuture<RpcResult<MonitorProfileDeleteOutput>> future =
212                         alivenessMonitorService.monitorProfileDelete(profileDeleteInput);
213                 LoggingFutures.addErrorLogging(future, LOG, "Delete monitor profile {}", interfaceName);
214             }
215         }
216     }
217
218     private static void createOrUpdateInterfaceMonitorIdMap(TypedReadWriteTransaction<Operational> tx, String infName,
219         long monitorId) throws ExecutionException, InterruptedException {
220         InterfaceMonitorId interfaceMonitorIdInstance;
221         List<Uint32> existingMonitorIds;
222         InterfaceMonitorIdBuilder interfaceMonitorIdBuilder = new InterfaceMonitorIdBuilder();
223         InstanceIdentifier<InterfaceMonitorId> id = InstanceIdentifier.builder(InterfaceMonitorIdMap.class)
224                 .child(InterfaceMonitorId.class, new InterfaceMonitorIdKey(infName)).build();
225         Optional<InterfaceMonitorId> interfaceMonitorIdMap = tx.read(id).get();
226         if (interfaceMonitorIdMap.isPresent()) {
227             interfaceMonitorIdInstance = interfaceMonitorIdMap.get();
228             existingMonitorIds = interfaceMonitorIdInstance.getMonitorId();
229             if (existingMonitorIds == null) {
230                 existingMonitorIds = new ArrayList<>();
231             }
232             if (!existingMonitorIds.contains(Uint32.valueOf(monitorId))) {
233                 existingMonitorIds.add(Uint32.valueOf(monitorId));
234                 interfaceMonitorIdInstance = interfaceMonitorIdBuilder.withKey(new InterfaceMonitorIdKey(infName))
235                         .setMonitorId(existingMonitorIds).build();
236                 tx.mergeParentStructureMerge(id, interfaceMonitorIdInstance);
237             }
238         } else {
239             existingMonitorIds = new ArrayList<>();
240             existingMonitorIds.add(Uint32.valueOf(monitorId));
241             interfaceMonitorIdInstance = interfaceMonitorIdBuilder.setMonitorId(existingMonitorIds)
242                     .withKey(new InterfaceMonitorIdKey(infName)).setInterfaceName(infName).build();
243             tx.mergeParentStructureMerge(id, interfaceMonitorIdInstance);
244         }
245     }
246
247     private static void createOrUpdateMonitorIdInterfaceMap(TypedReadWriteTransaction<Operational> tx, String infName,
248         long monitorId) throws ExecutionException, InterruptedException {
249         MonitorIdInterface monitorIdInterfaceInstance;
250         String existinginterfaceName;
251         MonitorIdInterfaceBuilder monitorIdInterfaceBuilder = new MonitorIdInterfaceBuilder();
252         InstanceIdentifier<MonitorIdInterface> id = InstanceIdentifier.builder(MonitorIdInterfaceMap.class)
253                 .child(MonitorIdInterface.class, new MonitorIdInterfaceKey(monitorId)).build();
254         Optional<MonitorIdInterface> monitorIdInterfaceMap = tx.read(id).get();
255         if (monitorIdInterfaceMap.isPresent()) {
256             monitorIdInterfaceInstance = monitorIdInterfaceMap.get();
257             existinginterfaceName = monitorIdInterfaceInstance.getInterfaceName();
258             if (!Objects.equals(existinginterfaceName, infName)) {
259                 monitorIdInterfaceInstance = monitorIdInterfaceBuilder.withKey(new MonitorIdInterfaceKey(monitorId))
260                         .setInterfaceName(infName).build();
261                 tx.mergeParentStructureMerge(id, monitorIdInterfaceInstance);
262             }
263         } else {
264             monitorIdInterfaceInstance = monitorIdInterfaceBuilder.setMonitorId(monitorId)
265                     .withKey(new MonitorIdInterfaceKey(monitorId)).setInterfaceName(infName).build();
266             tx.mergeParentStructureMerge(id, monitorIdInterfaceInstance);
267         }
268     }
269
270     private static List<Uint32> getMonitorIdForInterface(TypedReadTransaction<Operational> tx, String infName)
271         throws ExecutionException, InterruptedException {
272         InstanceIdentifier<InterfaceMonitorId> id = InstanceIdentifier.builder(InterfaceMonitorIdMap.class)
273                 .child(InterfaceMonitorId.class, new InterfaceMonitorIdKey(infName)).build();
274         return tx.read(id).get().map(InterfaceMonitorId::getMonitorId).orElse(null);
275     }
276
277     public Uint32 createMonitorProfile(MonitorProfileCreateInput monitorProfileCreateInput) {
278         try {
279             Future<RpcResult<MonitorProfileCreateOutput>> result = alivenessMonitorService
280                     .monitorProfileCreate(monitorProfileCreateInput);
281             RpcResult<MonitorProfileCreateOutput> rpcResult = result.get();
282             if (rpcResult.isSuccessful()) {
283                 return rpcResult.getResult().getProfileId();
284             } else {
285                 LOG.warn("RPC Call to Get Profile Id Id returned with Errors {}.. Trying to fetch existing profile ID",
286                         rpcResult.getErrors());
287                 Profile createProfile = monitorProfileCreateInput.getProfile();
288                 Future<RpcResult<MonitorProfileGetOutput>> existingProfile = alivenessMonitorService.monitorProfileGet(
289                         buildMonitorGetProfile(createProfile.getMonitorInterval().toJava(),
290                                 createProfile.getMonitorWindow().toJava(),
291                                 createProfile.getFailureThreshold().toJava(), createProfile.getProtocolType()));
292                 RpcResult<MonitorProfileGetOutput> rpcGetResult = existingProfile.get();
293                 if (rpcGetResult.isSuccessful()) {
294                     return rpcGetResult.getResult().getProfileId();
295                 } else {
296                     LOG.warn("RPC Call to Get Existing Profile Id returned with Errors {}", rpcGetResult.getErrors());
297                 }
298             }
299         } catch (InterruptedException | ExecutionException e) {
300             LOG.warn("Exception when allocating profile Id", e);
301         }
302         return Uint32.valueOf(0);
303     }
304
305     private static MonitorProfileGetInput buildMonitorGetProfile(long monitorInterval, long monitorWindow,
306             long failureThreshold, MonitorProtocolType protocolType) {
307         org.opendaylight.yang.gen.v1.urn.opendaylight.genius.alivenessmonitor
308             .rev160411.monitor.profile.get.input.ProfileBuilder profileBuilder =
309             new org.opendaylight.yang.gen.v1.urn.opendaylight
310             .genius.alivenessmonitor.rev160411.monitor.profile.get.input.ProfileBuilder();
311
312         profileBuilder.setFailureThreshold(failureThreshold);
313         profileBuilder.setMonitorInterval(monitorInterval);
314         profileBuilder.setMonitorWindow(monitorWindow);
315         profileBuilder.setProtocolType(protocolType);
316         MonitorProfileGetInputBuilder buildGetProfile = new MonitorProfileGetInputBuilder();
317         buildGetProfile.setProfile(profileBuilder.build());
318         return buildGetProfile.build();
319     }
320
321     public Uint32 allocateProfile(long failureThreshold, long monitoringInterval, long monitoringWindow,
322             MonitorProtocolType protoType) {
323         MonitorProfileCreateInput input = new MonitorProfileCreateInputBuilder().setProfile(
324                 new ProfileBuilder().setFailureThreshold(failureThreshold).setMonitorInterval(monitoringInterval)
325                         .setMonitorWindow(monitoringWindow).setProtocolType(protoType).build())
326                 .build();
327         return createMonitorProfile(input);
328     }
329
330     public static boolean lldpMonitoringEnabled(IfTunnel ifTunnel) {
331         return ifTunnel.isInternal() && ifTunnel.isMonitorEnabled()
332                 && TunnelMonitoringTypeLldp.class.isAssignableFrom(ifTunnel.getMonitorProtocol());
333     }
334 }