Fix wrong use of JobCoordinator in ElanInstanceManager
[netvirt.git] / vpnservice / elanmanager / elanmanager-impl / src / main / java / org / opendaylight / netvirt / elan / internal / ElanInstanceManager.java
1 /*
2  * Copyright (c) 2016 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
9 package org.opendaylight.netvirt.elan.internal;
10
11 import static java.util.Collections.emptyList;
12
13 import com.google.common.base.Optional;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18
19 import javax.annotation.Nonnull;
20 import javax.annotation.PostConstruct;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
27 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
28 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
29 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
30 import org.opendaylight.genius.mdsalutil.MDSALUtil;
31 import org.opendaylight.netvirt.elan.ElanException;
32 import org.opendaylight.netvirt.elan.utils.ElanConstants;
33 import org.opendaylight.netvirt.elan.utils.ElanUtils;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.Elan;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 @Singleton
50 public class ElanInstanceManager extends AsyncDataTreeChangeListenerBase<ElanInstance, ElanInstanceManager>
51         implements AutoCloseable {
52
53     private static final Logger LOG = LoggerFactory.getLogger(ElanInstanceManager.class);
54
55     private final DataBroker broker;
56     private final IdManagerService idManager;
57     private final IInterfaceManager interfaceManager;
58     private final ElanInterfaceManager elanInterfaceManager;
59
60     @Inject
61     public ElanInstanceManager(final DataBroker dataBroker, final IdManagerService managerService,
62                                final ElanInterfaceManager elanInterfaceManager,
63                                final IInterfaceManager interfaceManager) {
64         super(ElanInstance.class, ElanInstanceManager.class);
65         this.broker = dataBroker;
66         this.idManager = managerService;
67         this.elanInterfaceManager = elanInterfaceManager;
68         this.interfaceManager = interfaceManager;
69     }
70
71     @Override
72     @PostConstruct
73     public void init() {
74         registerListener(LogicalDatastoreType.CONFIGURATION, broker);
75     }
76
77     @Override
78     protected void remove(InstanceIdentifier<ElanInstance> identifier, ElanInstance deletedElan) {
79         LOG.trace("Remove ElanInstance - Key: {}, value: {}", identifier, deletedElan);
80         List<ListenableFuture<Void>> futures = new ArrayList<>();
81         String elanName = deletedElan.getElanInstanceName();
82         // check the elan Instance present in the Operational DataStore
83         Elan existingElan = ElanUtils.getElanByName(broker, elanName);
84         long elanTag = deletedElan.getElanTag();
85         // Cleaning up the existing Elan Instance
86         if (existingElan != null) {
87             List<String> elanInterfaces = existingElan.getElanInterfaces();
88             if (elanInterfaces != null && !elanInterfaces.isEmpty()) {
89                 for (String elanInterfaceName : elanInterfaces) {
90                     InstanceIdentifier<ElanInterface> elanInterfaceId = ElanUtils
91                             .getElanInterfaceConfigurationDataPathId(elanInterfaceName);
92                     InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(elanInterfaceName);
93                     futures.addAll(elanInterfaceManager.removeElanInterface(deletedElan, elanInterfaceName,
94                             interfaceInfo, false));
95                     ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION,
96                             elanInterfaceId);
97                 }
98             }
99             ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL,
100                     ElanUtils.getElanInstanceOperationalDataPath(elanName));
101             Optional<ElanDpnInterfacesList> elanDpnInterfaceList = MDSALUtil.read(broker,
102                     LogicalDatastoreType.OPERATIONAL,
103                     ElanUtils.getElanDpnOperationDataPath(elanName));
104             if (elanDpnInterfaceList.isPresent()) {
105                 ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL,
106                     getElanDpnOperationDataPath(elanName));
107             }
108             ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL,
109                     ElanUtils.getElanInfoEntriesOperationalDataPath(elanTag));
110         }
111         DataStoreJobCoordinator dataStoreJobCoordinator = DataStoreJobCoordinator.getInstance();
112         ElanUtils.removeAndGetElanInterfaces(elanName).forEach(elanInterfaceName -> {
113             dataStoreJobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(elanInterfaceName), () -> {
114                 WriteTransaction writeConfigTxn = broker.newWriteOnlyTransaction();
115                 LOG.info("Deleting the elanInterface present under ConfigDS:{}", elanInterfaceName);
116                 ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION,
117                         ElanUtils.getElanInterfaceConfigurationDataPathId(elanInterfaceName));
118                 elanInterfaceManager.unbindService(elanInterfaceName, writeConfigTxn);
119                 ElanUtils.removeElanInterfaceToElanInstanceCache(elanName, elanInterfaceName);
120                 LOG.info("unbind the Interface:{} service bounded to Elan:{}", elanInterfaceName, elanName);
121                 futures.add(writeConfigTxn.submit());
122                 return futures;
123             }, ElanConstants.JOB_MAX_RETRIES);
124         });
125         // Release tag
126         ElanUtils.releaseId(idManager, ElanConstants.ELAN_ID_POOL_NAME, elanName);
127         if (deletedElan.getAugmentation(EtreeInstance.class) != null) {
128             removeEtreeInstance(deletedElan);
129         }
130     }
131
132     private void removeEtreeInstance(ElanInstance deletedElan) {
133         // Release leaves tag
134         ElanUtils.releaseId(idManager, ElanConstants.ELAN_ID_POOL_NAME,
135                 deletedElan.getElanInstanceName() + ElanConstants.LEAVES_POSTFIX);
136
137         ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL,
138                 ElanUtils.getElanInfoEntriesOperationalDataPath(
139                 deletedElan.getAugmentation(EtreeInstance.class).getEtreeLeafTagVal().getValue()));
140     }
141
142     @Override
143     protected void update(InstanceIdentifier<ElanInstance> identifier, ElanInstance original, ElanInstance update) {
144         Long existingElanTag = original.getElanTag();
145         String elanName = update.getElanInstanceName();
146         if (existingElanTag != null && existingElanTag.equals(update.getElanTag())) {
147             return;
148         } else if (update.getElanTag() == null) {
149             // update the elan-Instance with new properties
150             WriteTransaction tx = broker.newWriteOnlyTransaction();
151             ElanUtils.updateOperationalDataStore(broker, idManager,
152                     update, new ArrayList<>(), tx);
153             ElanUtils.waitForTransactionToComplete(tx);
154             return;
155         }
156
157         DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
158         dataStoreCoordinator.enqueueJob(elanName, () -> {
159             try {
160                 return elanInterfaceManager.handleunprocessedElanInterfaces(update);
161             } catch (ElanException e) {
162                 LOG.error("update() failed for ElanInstance: " + identifier.toString(), e);
163                 return emptyList();
164             }
165         }, ElanConstants.JOB_MAX_RETRIES);
166
167     }
168
169     @Override
170     protected void add(InstanceIdentifier<ElanInstance> identifier, ElanInstance elanInstanceAdded) {
171         String elanInstanceName  = elanInstanceAdded.getElanInstanceName();
172         Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
173         if (elanInfo == null) {
174             WriteTransaction tx = broker.newWriteOnlyTransaction();
175             ElanUtils.updateOperationalDataStore(broker, idManager,
176                 elanInstanceAdded, new ArrayList<>(), tx);
177             ElanUtils.waitForTransactionToComplete(tx);
178         }
179     }
180
181     public ElanInstance getElanInstanceByName(String elanInstanceName) {
182         InstanceIdentifier<ElanInstance> elanIdentifierId = getElanInstanceConfigurationDataPath(elanInstanceName);
183         return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId).orNull();
184     }
185
186     @Nonnull
187     public List<DpnInterfaces> getElanDPNByName(String elanInstanceName) {
188         return getElanDPNByName(broker, elanInstanceName);
189     }
190
191     @Nonnull
192     public static List<DpnInterfaces> getElanDPNByName(DataBroker dataBroker, String elanInstanceName) {
193         InstanceIdentifier<ElanDpnInterfacesList> elanIdentifier = getElanDpnOperationDataPath(elanInstanceName);
194         return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanIdentifier).toJavaUtil().map(
195                 ElanDpnInterfacesList::getDpnInterfaces).orElse(Collections.emptyList());
196     }
197
198     private static InstanceIdentifier<ElanDpnInterfacesList> getElanDpnOperationDataPath(String elanInstanceName) {
199         return InstanceIdentifier.builder(ElanDpnInterfaces.class)
200                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
201     }
202
203     private InstanceIdentifier<ElanInstance> getElanInstanceConfigurationDataPath(String elanInstanceName) {
204         return InstanceIdentifier.builder(ElanInstances.class)
205                 .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
206     }
207
208     @Override
209     protected InstanceIdentifier<ElanInstance> getWildCardPath() {
210         return InstanceIdentifier.create(ElanInstances.class).child(ElanInstance.class);
211     }
212
213     @Override
214     protected ElanInstanceManager getDataTreeChangeListener() {
215         return this;
216     }
217 }