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.annotations.VisibleForTesting;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import com.google.common.util.concurrent.MoreExecutors;
16 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
17 import java.util.ArrayList;
18 import java.util.Date;
19 import java.util.List;
20 import java.util.Optional;
21 import java.util.concurrent.ExecutionException;
22 import org.opendaylight.lispflowmapping.lisp.util.LispAddressStringifier;
23 import org.opendaylight.mdsal.binding.api.DataBroker;
24 import org.opendaylight.mdsal.binding.api.ReadTransaction;
25 import org.opendaylight.mdsal.binding.api.TransactionChain;
26 import org.opendaylight.mdsal.binding.api.WriteTransaction;
27 import org.opendaylight.mdsal.common.api.CommitInfo;
28 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.XtrId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingDatabase;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingOrigin;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.db.instance.AuthenticationKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.db.instance.Mapping;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.db.instance.mapping.XtrIdMapping;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.mapping.database.LastUpdated;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.mapping.database.LastUpdatedBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.mapping.database.VirtualNetworkIdentifier;
38 import org.opendaylight.yangtools.yang.binding.DataObject;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.opendaylight.yangtools.yang.common.Empty;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 * Stores data coming from the mapping database RPCs into the MD-SAL datastore.
47 * @author Lorand Jakab
49 public class DataStoreBackEnd {
50 private static final Logger LOG = LoggerFactory.getLogger(DataStoreBackEnd.class);
51 private static final InstanceIdentifier<MappingDatabase> DATABASE_ROOT =
52 InstanceIdentifier.create(MappingDatabase.class);
53 private static final InstanceIdentifier<LastUpdated> LAST_UPDATED =
54 InstanceIdentifier.create(MappingDatabase.class).child(LastUpdated.class);
56 private final TransactionChain configTxChain;
57 private final TransactionChain operTxChain;
59 @SuppressFBWarnings(value = "MC_OVERRIDABLE_METHOD_CALL_IN_CONSTRUCTOR", justification = "Non-final for mocking")
60 public DataStoreBackEnd(DataBroker broker) {
61 LOG.debug("Creating DataStoreBackEnd transaction chain...");
62 configTxChain = broker.createMergingTransactionChain();
63 operTxChain = broker.createMergingTransactionChain();
64 configTxChain.addCallback(new FutureCallback<Empty>() {
66 public void onSuccess(Empty result) {
67 onTransactionChainSuccessful(configTxChain);
71 public void onFailure(Throwable cause) {
72 onTransactionChainFailed(configTxChain, cause);
75 operTxChain.addCallback(new FutureCallback<Empty>() {
77 public void onSuccess(Empty result) {
78 onTransactionChainSuccessful(operTxChain);
82 public void onFailure(Throwable cause) {
83 onTransactionChainFailed(operTxChain, cause);
88 public void addAuthenticationKey(AuthenticationKey authenticationKey) {
89 if (LOG.isDebugEnabled()) {
90 LOG.debug("MD-SAL: Adding authentication key '{}' for {}",
91 authenticationKey.getMappingAuthkey().getKeyString(),
92 LispAddressStringifier.getString(authenticationKey.getEid()));
95 InstanceIdentifier<AuthenticationKey> path = InstanceIdentifierUtil
96 .createAuthenticationKeyIid(authenticationKey.getEid());
97 writePutTransaction(path, authenticationKey, LogicalDatastoreType.CONFIGURATION,
98 "Adding authentication key to MD-SAL datastore failed");
101 public void addMapping(Mapping mapping) {
102 if (LOG.isDebugEnabled()) {
103 LOG.debug("MD-SAL: Adding mapping for {}",
104 LispAddressStringifier.getString(mapping.getMappingRecord().getEid()));
107 InstanceIdentifier<Mapping> path = InstanceIdentifierUtil
108 .createMappingIid(mapping.getMappingRecord().getEid(), mapping.getOrigin());
109 writePutTransaction(path, mapping, getDestinationDatastore(mapping),
110 "Adding mapping to MD-SAL datastore failed");
113 // This method assumes that it is only called for southbound originated Map-Registers
114 public void addXtrIdMapping(XtrIdMapping mapping) {
115 XtrId xtrId = mapping.getMappingRecord().getXtrId();
116 requireNonNull(xtrId, "Make sure you only call addXtrIdMapping when the MappingRecord contains an xTR-ID");
117 if (LOG.isDebugEnabled()) {
118 LOG.debug("MD-SAL: Adding mapping for {}, xTR-ID {}",
119 LispAddressStringifier.getString(mapping.getMappingRecord().getEid()), xtrId);
122 InstanceIdentifier<XtrIdMapping> path = InstanceIdentifierUtil
123 .createXtrIdMappingIid(mapping.getMappingRecord().getEid(), MappingOrigin.Southbound, xtrId);
124 writePutTransaction(path, mapping, LogicalDatastoreType.OPERATIONAL,
125 "Adding xTR-ID mapping to MD-SAL datastore failed");
128 public void removeAuthenticationKey(AuthenticationKey authenticationKey) {
129 if (LOG.isDebugEnabled()) {
130 LOG.debug("MD-SAL: Removing authentication key for {}",
131 LispAddressStringifier.getString(authenticationKey.getEid()));
134 InstanceIdentifier<AuthenticationKey> path = InstanceIdentifierUtil
135 .createAuthenticationKeyIid(authenticationKey.getEid());
136 deleteTransaction(path, LogicalDatastoreType.CONFIGURATION,
137 "Deleting authentication key from MD-SAL datastore failed");
140 public void removeMapping(Mapping mapping) {
141 if (LOG.isDebugEnabled()) {
142 LOG.debug("MD-SAL: Removing mapping for {}",
143 LispAddressStringifier.getString(mapping.getMappingRecord().getEid()));
146 InstanceIdentifier<Mapping> path = InstanceIdentifierUtil
147 .createMappingIid(mapping.getMappingRecord().getEid(), mapping.getOrigin());
148 deleteTransaction(path, getDestinationDatastore(mapping), "Deleting mapping from MD-SAL datastore failed");
151 public void removeXtrIdMapping(XtrIdMapping mapping) {
152 XtrId xtrId = mapping.getMappingRecord().getXtrId();
153 requireNonNull(xtrId, "Make sure you only call addXtrIdMapping when the MappingRecord contains an xTR-ID");
154 if (LOG.isDebugEnabled()) {
155 LOG.debug("MD-SAL: Removing mapping for {}, xTR-ID {}",
156 LispAddressStringifier.getString(mapping.getMappingRecord().getEid()), xtrId);
159 InstanceIdentifier<XtrIdMapping> path = InstanceIdentifierUtil
160 .createXtrIdMappingIid(mapping.getMappingRecord().getEid(), MappingOrigin.Southbound, xtrId);
161 deleteTransaction(path, LogicalDatastoreType.OPERATIONAL,
162 "Deleting xTR-ID mapping from MD-SAL datastore failed");
165 public void removeAllDatastoreContent() {
166 LOG.debug("MD-SAL: Removing all mapping database datastore content (mappings and keys)");
167 removeAllConfigDatastoreContent();
168 removeAllOperationalDatastoreContent();
171 public void removeAllConfigDatastoreContent() {
172 deleteTransaction(DATABASE_ROOT, LogicalDatastoreType.CONFIGURATION,
173 "Removal of all database content in config datastore failed");
176 public void removeAllOperationalDatastoreContent() {
177 deleteTransaction(DATABASE_ROOT, LogicalDatastoreType.OPERATIONAL,
178 "Removal of all database content in operational datastore failed");
181 public void updateAuthenticationKey(AuthenticationKey authenticationKey) {
182 if (LOG.isDebugEnabled()) {
183 LOG.debug("MD-SAL: Updating authentication key for {} with '{}'",
184 LispAddressStringifier.getString(authenticationKey.getEid()),
185 authenticationKey.getMappingAuthkey().getKeyString());
188 InstanceIdentifier<AuthenticationKey> path = InstanceIdentifierUtil
189 .createAuthenticationKeyIid(authenticationKey.getEid());
190 writePutTransaction(path, authenticationKey, LogicalDatastoreType.CONFIGURATION,
191 "Updating authentication key in MD-SAL datastore failed");
194 public void updateMapping(Mapping mapping) {
195 if (LOG.isDebugEnabled()) {
196 LOG.debug("MD-SAL: Updating mapping for {}",
197 LispAddressStringifier.getString(mapping.getMappingRecord().getEid()));
200 InstanceIdentifier<Mapping> path = InstanceIdentifierUtil
201 .createMappingIid(mapping.getMappingRecord().getEid(), mapping.getOrigin());
202 writePutTransaction(path, mapping, getDestinationDatastore(mapping),
203 "Updating mapping in MD-SAL datastore failed");
206 public List<Mapping> getAllMappings() {
207 List<Mapping> mappings = getAllMappings(LogicalDatastoreType.CONFIGURATION);
208 mappings.addAll(getAllMappings(LogicalDatastoreType.OPERATIONAL));
212 public List<Mapping> getAllMappings(LogicalDatastoreType logicalDataStore) {
213 LOG.debug("MD-SAL: Get all mappings from {} datastore",
214 logicalDataStore == LogicalDatastoreType.CONFIGURATION ? "config" : "operational");
215 List<Mapping> mappings = new ArrayList<>();
216 MappingDatabase mdb = readTransaction(DATABASE_ROOT, logicalDataStore);
218 if (mdb != null && mdb.getVirtualNetworkIdentifier() != null) {
219 for (VirtualNetworkIdentifier id : mdb.nonnullVirtualNetworkIdentifier().values()) {
220 List<Mapping> ms = new ArrayList<>(id.nonnullMapping().values());
230 public List<AuthenticationKey> getAllAuthenticationKeys() {
231 LOG.debug("MD-SAL: Get all authentication keys from datastore");
232 List<AuthenticationKey> authKeys = new ArrayList<>();
233 MappingDatabase mdb = readTransaction(DATABASE_ROOT, LogicalDatastoreType.CONFIGURATION);
235 if (mdb != null && mdb.getVirtualNetworkIdentifier() != null) {
236 for (VirtualNetworkIdentifier id : mdb.nonnullVirtualNetworkIdentifier().values()) {
237 List<AuthenticationKey> keys = new ArrayList<>(id.nonnullAuthenticationKey().values());
239 authKeys.addAll(keys);
247 public void saveLastUpdateTimestamp() {
248 Long timestamp = System.currentTimeMillis();
249 LOG.debug("MD-SAL: Saving last update timestamp to operational datastore: {}", new Date(timestamp));
250 writePutTransaction(LAST_UPDATED, new LastUpdatedBuilder().setLastUpdated(timestamp).build(),
251 LogicalDatastoreType.OPERATIONAL, "Couldn't save last update timestamp to operational datastore");
254 public void removeLastUpdateTimestamp() {
255 LOG.debug("MD-SAL: Removing last update timestamp from operational datastore");
256 deleteTransaction(LAST_UPDATED, LogicalDatastoreType.OPERATIONAL,
257 "Couldn't remove last update timestamp from operational datastore");
260 public Long getLastUpdateTimestamp() {
261 LastUpdated lastUpdated = readTransaction(LAST_UPDATED, LogicalDatastoreType.OPERATIONAL);
262 if (lastUpdated != null && lastUpdated.getLastUpdated() != null) {
263 Long timestamp = lastUpdated.getLastUpdated();
264 LOG.debug("MD-SAL: Retrieved last update timestamp from operational datastore: {}",
265 new Date(timestamp).toString());
268 LOG.debug("MD-SAL: Couldn't retrieve last update timestamp from operational datastore");
273 private static LogicalDatastoreType getDestinationDatastore(Mapping mapping) {
274 return mapping.getOrigin().equals(MappingOrigin.Southbound) ? LogicalDatastoreType.OPERATIONAL
275 : LogicalDatastoreType.CONFIGURATION;
278 private TransactionChain getChain(LogicalDatastoreType logicalDatastoreType) {
279 return switch (logicalDatastoreType) {
280 case CONFIGURATION -> configTxChain;
281 case OPERATIONAL -> operTxChain;
285 private <U extends DataObject> void writePutTransaction(InstanceIdentifier<U> addIID, U data,
286 LogicalDatastoreType logicalDatastoreType, String errMsg) {
287 WriteTransaction writeTx = getChain(logicalDatastoreType).newWriteOnlyTransaction();
288 // TODO: is is a utility method, hence we do not have enough lifecycle knowledge to use plain put()
289 writeTx.mergeParentStructurePut(logicalDatastoreType, addIID, data);
290 writeTx.commit().addCallback(new FutureCallback<CommitInfo>() {
292 public void onSuccess(CommitInfo result) {
297 public void onFailure(Throwable throwable) {
298 LOG.error("Transaction failed:", throwable);
300 }, MoreExecutors.directExecutor());
303 private <U extends DataObject> U readTransaction(InstanceIdentifier<U> readIID,
304 LogicalDatastoreType logicalDatastoreType) {
305 final ListenableFuture<Optional<U>> readFuture;
306 try (ReadTransaction readTx = getChain(logicalDatastoreType).newReadOnlyTransaction()) {
307 readFuture = readTx.read(logicalDatastoreType, readIID);
310 Optional<U> optionalDataObject = readFuture.get();
311 if (optionalDataObject != null && optionalDataObject.isPresent()) {
312 return optionalDataObject.orElseThrow();
314 LOG.debug("{}: Failed to read", Thread.currentThread().getStackTrace()[1]);
316 } catch (InterruptedException | ExecutionException e) {
317 LOG.warn("Failed to ....", e);
322 private <U extends DataObject> void deleteTransaction(InstanceIdentifier<U> deleteIID,
323 LogicalDatastoreType logicalDatastoreType, String errMsg) {
324 WriteTransaction writeTx = getChain(logicalDatastoreType).newWriteOnlyTransaction();
325 writeTx.delete(logicalDatastoreType, deleteIID);
326 writeTx.commit().addCallback(new FutureCallback<CommitInfo>() {
328 public void onSuccess(CommitInfo result) {
332 public void onFailure(Throwable throwable) {
333 LOG.error("Transaction failed:", throwable);
335 }, MoreExecutors.directExecutor());
339 void onTransactionChainFailed(TransactionChain chain, Throwable cause) {
340 LOG.error("Broken chain {} in DataStoreBackEnd, cause {}", chain, cause.getMessage());
344 void onTransactionChainSuccessful(TransactionChain chain) {
345 LOG.info("DataStoreBackEnd closed successfully, chain {}", chain);
348 public void closeTransactionChain() {
349 LOG.debug("Closing DataStoreBackEnd transaction chain...");
350 configTxChain.close();