2 * Copyright (c) 2015 Cisco Systems, Inc. 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.lispflowmapping.dsbackend;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import com.google.common.util.concurrent.MoreExecutors;
15 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
16 import java.util.ArrayList;
17 import java.util.Date;
18 import java.util.List;
19 import java.util.Optional;
20 import java.util.concurrent.ExecutionException;
21 import org.opendaylight.lispflowmapping.lisp.util.LispAddressStringifier;
22 import org.opendaylight.mdsal.binding.api.DataBroker;
23 import org.opendaylight.mdsal.binding.api.ReadTransaction;
24 import org.opendaylight.mdsal.binding.api.Transaction;
25 import org.opendaylight.mdsal.binding.api.TransactionChain;
26 import org.opendaylight.mdsal.binding.api.TransactionChainListener;
27 import org.opendaylight.mdsal.binding.api.WriteTransaction;
28 import org.opendaylight.mdsal.common.api.CommitInfo;
29 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.XtrId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingDatabase;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingOrigin;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.db.instance.AuthenticationKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.db.instance.Mapping;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.db.instance.mapping.XtrIdMapping;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.mapping.database.LastUpdated;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.mapping.database.LastUpdatedBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.mapping.database.VirtualNetworkIdentifier;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
44 * Stores data coming from the mapping database RPCs into the MD-SAL datastore.
46 * @author Lorand Jakab
48 public class DataStoreBackEnd implements TransactionChainListener {
49 private static final Logger LOG = LoggerFactory.getLogger(DataStoreBackEnd.class);
50 private static final InstanceIdentifier<MappingDatabase> DATABASE_ROOT =
51 InstanceIdentifier.create(MappingDatabase.class);
52 private static final InstanceIdentifier<LastUpdated> LAST_UPDATED =
53 InstanceIdentifier.create(MappingDatabase.class).child(LastUpdated.class);
55 private final TransactionChain configTxChain;
56 private final TransactionChain operTxChain;
58 @SuppressFBWarnings(value = "MC_OVERRIDABLE_METHOD_CALL_IN_CONSTRUCTOR", justification = "Non-final for mocking")
59 public DataStoreBackEnd(DataBroker broker) {
60 LOG.debug("Creating DataStoreBackEnd transaction chain...");
61 configTxChain = broker.createMergingTransactionChain(this);
62 operTxChain = broker.createMergingTransactionChain(this);
65 public void addAuthenticationKey(AuthenticationKey authenticationKey) {
66 if (LOG.isDebugEnabled()) {
67 LOG.debug("MD-SAL: Adding authentication key '{}' for {}",
68 authenticationKey.getMappingAuthkey().getKeyString(),
69 LispAddressStringifier.getString(authenticationKey.getEid()));
72 InstanceIdentifier<AuthenticationKey> path = InstanceIdentifierUtil
73 .createAuthenticationKeyIid(authenticationKey.getEid());
74 writePutTransaction(path, authenticationKey, LogicalDatastoreType.CONFIGURATION,
75 "Adding authentication key to MD-SAL datastore failed");
78 public void addMapping(Mapping mapping) {
79 if (LOG.isDebugEnabled()) {
80 LOG.debug("MD-SAL: Adding mapping for {}",
81 LispAddressStringifier.getString(mapping.getMappingRecord().getEid()));
84 InstanceIdentifier<Mapping> path = InstanceIdentifierUtil
85 .createMappingIid(mapping.getMappingRecord().getEid(), mapping.getOrigin());
86 writePutTransaction(path, mapping, getDestinationDatastore(mapping),
87 "Adding mapping to MD-SAL datastore failed");
90 // This method assumes that it is only called for southbound originated Map-Registers
91 public void addXtrIdMapping(XtrIdMapping mapping) {
92 XtrId xtrId = mapping.getMappingRecord().getXtrId();
93 requireNonNull(xtrId, "Make sure you only call addXtrIdMapping when the MappingRecord contains an xTR-ID");
94 if (LOG.isDebugEnabled()) {
95 LOG.debug("MD-SAL: Adding mapping for {}, xTR-ID {}",
96 LispAddressStringifier.getString(mapping.getMappingRecord().getEid()), xtrId);
99 InstanceIdentifier<XtrIdMapping> path = InstanceIdentifierUtil
100 .createXtrIdMappingIid(mapping.getMappingRecord().getEid(), MappingOrigin.Southbound, xtrId);
101 writePutTransaction(path, mapping, LogicalDatastoreType.OPERATIONAL,
102 "Adding xTR-ID mapping to MD-SAL datastore failed");
105 public void removeAuthenticationKey(AuthenticationKey authenticationKey) {
106 if (LOG.isDebugEnabled()) {
107 LOG.debug("MD-SAL: Removing authentication key for {}",
108 LispAddressStringifier.getString(authenticationKey.getEid()));
111 InstanceIdentifier<AuthenticationKey> path = InstanceIdentifierUtil
112 .createAuthenticationKeyIid(authenticationKey.getEid());
113 deleteTransaction(path, LogicalDatastoreType.CONFIGURATION,
114 "Deleting authentication key from MD-SAL datastore failed");
117 public void removeMapping(Mapping mapping) {
118 if (LOG.isDebugEnabled()) {
119 LOG.debug("MD-SAL: Removing mapping for {}",
120 LispAddressStringifier.getString(mapping.getMappingRecord().getEid()));
123 InstanceIdentifier<Mapping> path = InstanceIdentifierUtil
124 .createMappingIid(mapping.getMappingRecord().getEid(), mapping.getOrigin());
125 deleteTransaction(path, getDestinationDatastore(mapping), "Deleting mapping from MD-SAL datastore failed");
128 public void removeXtrIdMapping(XtrIdMapping mapping) {
129 XtrId xtrId = mapping.getMappingRecord().getXtrId();
130 requireNonNull(xtrId, "Make sure you only call addXtrIdMapping when the MappingRecord contains an xTR-ID");
131 if (LOG.isDebugEnabled()) {
132 LOG.debug("MD-SAL: Removing mapping for {}, xTR-ID {}",
133 LispAddressStringifier.getString(mapping.getMappingRecord().getEid()), xtrId);
136 InstanceIdentifier<XtrIdMapping> path = InstanceIdentifierUtil
137 .createXtrIdMappingIid(mapping.getMappingRecord().getEid(), MappingOrigin.Southbound, xtrId);
138 deleteTransaction(path, LogicalDatastoreType.OPERATIONAL,
139 "Deleting xTR-ID mapping from MD-SAL datastore failed");
142 public void removeAllDatastoreContent() {
143 LOG.debug("MD-SAL: Removing all mapping database datastore content (mappings and keys)");
144 removeAllConfigDatastoreContent();
145 removeAllOperationalDatastoreContent();
148 public void removeAllConfigDatastoreContent() {
149 deleteTransaction(DATABASE_ROOT, LogicalDatastoreType.CONFIGURATION,
150 "Removal of all database content in config datastore failed");
153 public void removeAllOperationalDatastoreContent() {
154 deleteTransaction(DATABASE_ROOT, LogicalDatastoreType.OPERATIONAL,
155 "Removal of all database content in operational datastore failed");
158 public void updateAuthenticationKey(AuthenticationKey authenticationKey) {
159 if (LOG.isDebugEnabled()) {
160 LOG.debug("MD-SAL: Updating authentication key for {} with '{}'",
161 LispAddressStringifier.getString(authenticationKey.getEid()),
162 authenticationKey.getMappingAuthkey().getKeyString());
165 InstanceIdentifier<AuthenticationKey> path = InstanceIdentifierUtil
166 .createAuthenticationKeyIid(authenticationKey.getEid());
167 writePutTransaction(path, authenticationKey, LogicalDatastoreType.CONFIGURATION,
168 "Updating authentication key in MD-SAL datastore failed");
171 public void updateMapping(Mapping mapping) {
172 if (LOG.isDebugEnabled()) {
173 LOG.debug("MD-SAL: Updating mapping for {}",
174 LispAddressStringifier.getString(mapping.getMappingRecord().getEid()));
177 InstanceIdentifier<Mapping> path = InstanceIdentifierUtil
178 .createMappingIid(mapping.getMappingRecord().getEid(), mapping.getOrigin());
179 writePutTransaction(path, mapping, getDestinationDatastore(mapping),
180 "Updating mapping in MD-SAL datastore failed");
183 public List<Mapping> getAllMappings() {
184 List<Mapping> mappings = getAllMappings(LogicalDatastoreType.CONFIGURATION);
185 mappings.addAll(getAllMappings(LogicalDatastoreType.OPERATIONAL));
189 public List<Mapping> getAllMappings(LogicalDatastoreType logicalDataStore) {
190 LOG.debug("MD-SAL: Get all mappings from {} datastore",
191 logicalDataStore == LogicalDatastoreType.CONFIGURATION ? "config" : "operational");
192 List<Mapping> mappings = new ArrayList<>();
193 MappingDatabase mdb = readTransaction(DATABASE_ROOT, logicalDataStore);
195 if (mdb != null && mdb.getVirtualNetworkIdentifier() != null) {
196 for (VirtualNetworkIdentifier id : mdb.nonnullVirtualNetworkIdentifier().values()) {
197 List<Mapping> ms = new ArrayList<>(id.nonnullMapping().values());
207 public List<AuthenticationKey> getAllAuthenticationKeys() {
208 LOG.debug("MD-SAL: Get all authentication keys from datastore");
209 List<AuthenticationKey> authKeys = new ArrayList<>();
210 MappingDatabase mdb = readTransaction(DATABASE_ROOT, LogicalDatastoreType.CONFIGURATION);
212 if (mdb != null && mdb.getVirtualNetworkIdentifier() != null) {
213 for (VirtualNetworkIdentifier id : mdb.nonnullVirtualNetworkIdentifier().values()) {
214 List<AuthenticationKey> keys = new ArrayList<>(id.nonnullAuthenticationKey().values());
216 authKeys.addAll(keys);
224 public void saveLastUpdateTimestamp() {
225 Long timestamp = System.currentTimeMillis();
226 LOG.debug("MD-SAL: Saving last update timestamp to operational datastore: {}", new Date(timestamp).toString());
227 writePutTransaction(LAST_UPDATED, new LastUpdatedBuilder().setLastUpdated(timestamp).build(),
228 LogicalDatastoreType.OPERATIONAL, "Couldn't save last update timestamp to operational datastore");
231 public void removeLastUpdateTimestamp() {
232 LOG.debug("MD-SAL: Removing last update timestamp from operational datastore");
233 deleteTransaction(LAST_UPDATED, LogicalDatastoreType.OPERATIONAL,
234 "Couldn't remove last update timestamp from operational datastore");
237 public Long getLastUpdateTimestamp() {
238 LastUpdated lastUpdated = readTransaction(LAST_UPDATED, LogicalDatastoreType.OPERATIONAL);
239 if (lastUpdated != null && lastUpdated.getLastUpdated() != null) {
240 Long timestamp = lastUpdated.getLastUpdated();
241 LOG.debug("MD-SAL: Retrieved last update timestamp from operational datastore: {}",
242 new Date(timestamp).toString());
245 LOG.debug("MD-SAL: Couldn't retrieve last update timestamp from operational datastore");
250 private static LogicalDatastoreType getDestinationDatastore(Mapping mapping) {
251 return mapping.getOrigin().equals(MappingOrigin.Southbound) ? LogicalDatastoreType.OPERATIONAL
252 : LogicalDatastoreType.CONFIGURATION;
255 private TransactionChain getChain(LogicalDatastoreType logicalDatastoreType) {
256 return switch (logicalDatastoreType) {
257 case CONFIGURATION -> configTxChain;
258 case OPERATIONAL -> operTxChain;
262 private <U extends org.opendaylight.yangtools.yang.binding.DataObject> void writePutTransaction(
263 InstanceIdentifier<U> addIID, U data, LogicalDatastoreType logicalDatastoreType, String errMsg) {
264 WriteTransaction writeTx = getChain(logicalDatastoreType).newWriteOnlyTransaction();
265 // TODO: is is a utility method, hence we do not have enough lifecycle knowledge to use plain put()
266 writeTx.mergeParentStructurePut(logicalDatastoreType, addIID, data);
267 writeTx.commit().addCallback(new FutureCallback<CommitInfo>() {
270 public void onSuccess(CommitInfo result) {
274 public void onFailure(Throwable throwable) {
275 LOG.error("Transaction failed:", throwable);
277 }, MoreExecutors.directExecutor());
280 private <U extends org.opendaylight.yangtools.yang.binding.DataObject> U readTransaction(
281 InstanceIdentifier<U> readIID, LogicalDatastoreType logicalDatastoreType) {
282 final ListenableFuture<Optional<U>> readFuture;
283 try (ReadTransaction readTx = getChain(logicalDatastoreType).newReadOnlyTransaction()) {
284 readFuture = readTx.read(logicalDatastoreType, readIID);
287 Optional<U> optionalDataObject = readFuture.get();
288 if (optionalDataObject != null && optionalDataObject.isPresent()) {
289 return optionalDataObject.orElseThrow();
291 LOG.debug("{}: Failed to read", Thread.currentThread().getStackTrace()[1]);
293 } catch (InterruptedException | ExecutionException e) {
294 LOG.warn("Failed to ....", e);
299 private <U extends org.opendaylight.yangtools.yang.binding.DataObject> void deleteTransaction(
300 InstanceIdentifier<U> deleteIID, LogicalDatastoreType logicalDatastoreType, String errMsg) {
301 WriteTransaction writeTx = getChain(logicalDatastoreType).newWriteOnlyTransaction();
302 writeTx.delete(logicalDatastoreType, deleteIID);
303 writeTx.commit().addCallback(new FutureCallback<CommitInfo>() {
305 public void onSuccess(CommitInfo result) {
309 public void onFailure(Throwable throwable) {
310 LOG.error("Transaction failed:", throwable);
312 }, MoreExecutors.directExecutor());
316 public void onTransactionChainFailed(TransactionChain chain, Transaction transaction, Throwable cause) {
317 LOG.error("Broken chain {} in DataStoreBackEnd, transaction {}, cause {}", chain, transaction.getIdentifier(),
322 public void onTransactionChainSuccessful(TransactionChain chain) {
323 LOG.info("DataStoreBackEnd closed successfully, chain {}", chain);
326 public void closeTransactionChain() {
327 LOG.debug("Closing DataStoreBackEnd transaction chain...");
328 configTxChain.close();