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 java.util.ArrayList;
16 import java.util.Date;
17 import java.util.List;
18 import java.util.Optional;
19 import java.util.concurrent.ExecutionException;
20 import org.opendaylight.lispflowmapping.lisp.util.LispAddressStringifier;
21 import org.opendaylight.mdsal.binding.api.DataBroker;
22 import org.opendaylight.mdsal.binding.api.ReadTransaction;
23 import org.opendaylight.mdsal.binding.api.Transaction;
24 import org.opendaylight.mdsal.binding.api.TransactionChain;
25 import org.opendaylight.mdsal.binding.api.TransactionChainListener;
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.InstanceIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
43 * Stores data coming from the mapping database RPCs into the MD-SAL datastore.
45 * @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);
54 private final DataBroker broker;
55 private TransactionChain txChain;
57 public DataStoreBackEnd(DataBroker broker) {
59 createTransactionChain();
62 public void createTransactionChain() {
63 LOG.debug("Creating DataStoreBackEnd transaction chain...");
64 txChain = broker.createMergingTransactionChain(this);
67 public void addAuthenticationKey(AuthenticationKey authenticationKey) {
68 if (LOG.isDebugEnabled()) {
69 LOG.debug("MD-SAL: Adding authentication key '{}' for {}",
70 authenticationKey.getMappingAuthkey().getKeyString(),
71 LispAddressStringifier.getString(authenticationKey.getEid()));
74 InstanceIdentifier<AuthenticationKey> path = InstanceIdentifierUtil
75 .createAuthenticationKeyIid(authenticationKey.getEid());
76 writePutTransaction(path, authenticationKey, LogicalDatastoreType.CONFIGURATION,
77 "Adding authentication key to MD-SAL datastore failed");
80 public void addMapping(Mapping mapping) {
81 if (LOG.isDebugEnabled()) {
82 LOG.debug("MD-SAL: Adding mapping for {}",
83 LispAddressStringifier.getString(mapping.getMappingRecord().getEid()));
86 InstanceIdentifier<Mapping> path = InstanceIdentifierUtil
87 .createMappingIid(mapping.getMappingRecord().getEid(), mapping.getOrigin());
88 writePutTransaction(path, mapping, getDestinationDatastore(mapping),
89 "Adding mapping to MD-SAL datastore failed");
92 // This method assumes that it is only called for southbound originated Map-Registers
93 public void addXtrIdMapping(XtrIdMapping mapping) {
94 XtrId xtrId = mapping.getMappingRecord().getXtrId();
95 requireNonNull(xtrId, "Make sure you only call addXtrIdMapping when the MappingRecord contains an xTR-ID");
96 if (LOG.isDebugEnabled()) {
97 LOG.debug("MD-SAL: Adding mapping for {}, xTR-ID {}",
98 LispAddressStringifier.getString(mapping.getMappingRecord().getEid()), xtrId);
101 InstanceIdentifier<XtrIdMapping> path = InstanceIdentifierUtil
102 .createXtrIdMappingIid(mapping.getMappingRecord().getEid(), MappingOrigin.Southbound, xtrId);
103 writePutTransaction(path, mapping, LogicalDatastoreType.OPERATIONAL,
104 "Adding xTR-ID mapping to MD-SAL datastore failed");
107 public void removeAuthenticationKey(AuthenticationKey authenticationKey) {
108 if (LOG.isDebugEnabled()) {
109 LOG.debug("MD-SAL: Removing authentication key for {}",
110 LispAddressStringifier.getString(authenticationKey.getEid()));
113 InstanceIdentifier<AuthenticationKey> path = InstanceIdentifierUtil
114 .createAuthenticationKeyIid(authenticationKey.getEid());
115 deleteTransaction(path, LogicalDatastoreType.CONFIGURATION,
116 "Deleting authentication key from MD-SAL datastore failed");
119 public void removeMapping(Mapping mapping) {
120 if (LOG.isDebugEnabled()) {
121 LOG.debug("MD-SAL: Removing mapping for {}",
122 LispAddressStringifier.getString(mapping.getMappingRecord().getEid()));
125 InstanceIdentifier<Mapping> path = InstanceIdentifierUtil
126 .createMappingIid(mapping.getMappingRecord().getEid(), mapping.getOrigin());
127 deleteTransaction(path, getDestinationDatastore(mapping), "Deleting mapping from MD-SAL datastore failed");
130 public void removeXtrIdMapping(XtrIdMapping mapping) {
131 XtrId xtrId = mapping.getMappingRecord().getXtrId();
132 requireNonNull(xtrId, "Make sure you only call addXtrIdMapping when the MappingRecord contains an xTR-ID");
133 if (LOG.isDebugEnabled()) {
134 LOG.debug("MD-SAL: Removing mapping for {}, xTR-ID {}",
135 LispAddressStringifier.getString(mapping.getMappingRecord().getEid()), xtrId);
138 InstanceIdentifier<XtrIdMapping> path = InstanceIdentifierUtil
139 .createXtrIdMappingIid(mapping.getMappingRecord().getEid(), MappingOrigin.Southbound, xtrId);
140 deleteTransaction(path, LogicalDatastoreType.OPERATIONAL,
141 "Deleting xTR-ID mapping from MD-SAL datastore failed");
144 public void removeAllDatastoreContent() {
145 LOG.debug("MD-SAL: Removing all mapping database datastore content (mappings and keys)");
146 removeAllConfigDatastoreContent();
147 removeAllOperationalDatastoreContent();
150 public void removeAllConfigDatastoreContent() {
151 deleteTransaction(DATABASE_ROOT, LogicalDatastoreType.CONFIGURATION,
152 "Removal of all database content in config datastore failed");
155 public void removeAllOperationalDatastoreContent() {
156 deleteTransaction(DATABASE_ROOT, LogicalDatastoreType.OPERATIONAL,
157 "Removal of all database content in operational datastore failed");
160 public void updateAuthenticationKey(AuthenticationKey authenticationKey) {
161 if (LOG.isDebugEnabled()) {
162 LOG.debug("MD-SAL: Updating authentication key for {} with '{}'",
163 LispAddressStringifier.getString(authenticationKey.getEid()),
164 authenticationKey.getMappingAuthkey().getKeyString());
167 InstanceIdentifier<AuthenticationKey> path = InstanceIdentifierUtil
168 .createAuthenticationKeyIid(authenticationKey.getEid());
169 writePutTransaction(path, authenticationKey, LogicalDatastoreType.CONFIGURATION,
170 "Updating authentication key in MD-SAL datastore failed");
173 public void updateMapping(Mapping mapping) {
174 if (LOG.isDebugEnabled()) {
175 LOG.debug("MD-SAL: Updating mapping for {}",
176 LispAddressStringifier.getString(mapping.getMappingRecord().getEid()));
179 InstanceIdentifier<Mapping> path = InstanceIdentifierUtil
180 .createMappingIid(mapping.getMappingRecord().getEid(), mapping.getOrigin());
181 writePutTransaction(path, mapping, getDestinationDatastore(mapping),
182 "Updating mapping in MD-SAL datastore failed");
185 public List<Mapping> getAllMappings() {
186 List<Mapping> mappings = getAllMappings(LogicalDatastoreType.CONFIGURATION);
187 mappings.addAll(getAllMappings(LogicalDatastoreType.OPERATIONAL));
191 public List<Mapping> getAllMappings(LogicalDatastoreType logicalDataStore) {
192 LOG.debug("MD-SAL: Get all mappings from {} datastore",
193 logicalDataStore == LogicalDatastoreType.CONFIGURATION ? "config" : "operational");
194 List<Mapping> mappings = new ArrayList<>();
195 MappingDatabase mdb = readTransaction(DATABASE_ROOT, logicalDataStore);
197 if (mdb != null && mdb.getVirtualNetworkIdentifier() != null) {
198 for (VirtualNetworkIdentifier id : mdb.nonnullVirtualNetworkIdentifier().values()) {
199 List<Mapping> ms = new ArrayList<>(id.nonnullMapping().values());
209 public List<AuthenticationKey> getAllAuthenticationKeys() {
210 LOG.debug("MD-SAL: Get all authentication keys from datastore");
211 List<AuthenticationKey> authKeys = new ArrayList<>();
212 MappingDatabase mdb = readTransaction(DATABASE_ROOT, LogicalDatastoreType.CONFIGURATION);
214 if (mdb != null && mdb.getVirtualNetworkIdentifier() != null) {
215 for (VirtualNetworkIdentifier id : mdb.nonnullVirtualNetworkIdentifier().values()) {
216 List<AuthenticationKey> keys = new ArrayList<>(id.nonnullAuthenticationKey().values());
218 authKeys.addAll(keys);
226 public void saveLastUpdateTimestamp() {
227 Long timestamp = System.currentTimeMillis();
228 LOG.debug("MD-SAL: Saving last update timestamp to operational datastore: {}", new Date(timestamp).toString());
229 writePutTransaction(LAST_UPDATED, new LastUpdatedBuilder().setLastUpdated(timestamp).build(),
230 LogicalDatastoreType.OPERATIONAL, "Couldn't save last update timestamp to operational datastore");
233 public void removeLastUpdateTimestamp() {
234 LOG.debug("MD-SAL: Removing last update timestamp from operational datastore");
235 deleteTransaction(LAST_UPDATED, LogicalDatastoreType.OPERATIONAL,
236 "Couldn't remove last update timestamp from operational datastore");
239 public Long getLastUpdateTimestamp() {
240 LastUpdated lastUpdated = readTransaction(LAST_UPDATED, LogicalDatastoreType.OPERATIONAL);
241 if (lastUpdated != null && lastUpdated.getLastUpdated() != null) {
242 Long timestamp = lastUpdated.getLastUpdated();
243 LOG.debug("MD-SAL: Retrieved last update timestamp from operational datastore: {}",
244 new Date(timestamp).toString());
247 LOG.debug("MD-SAL: Couldn't retrieve last update timestamp from operational datastore");
252 private static LogicalDatastoreType getDestinationDatastore(Mapping mapping) {
253 return mapping.getOrigin().equals(MappingOrigin.Southbound) ? LogicalDatastoreType.OPERATIONAL
254 : LogicalDatastoreType.CONFIGURATION;
257 private <U extends org.opendaylight.yangtools.yang.binding.DataObject> void writePutTransaction(
258 InstanceIdentifier<U> addIID, U data, LogicalDatastoreType logicalDatastoreType, String errMsg) {
259 WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
260 // TODO: is is a utility method, hence we do not have enough lifecycle knowledge to use plain put()
261 writeTx.mergeParentStructurePut(logicalDatastoreType, addIID, data);
262 writeTx.commit().addCallback(new FutureCallback<CommitInfo>() {
265 public void onSuccess(CommitInfo result) {
269 public void onFailure(Throwable throwable) {
270 LOG.error("Transaction failed:", throwable);
272 }, MoreExecutors.directExecutor());
275 private <U extends org.opendaylight.yangtools.yang.binding.DataObject> U readTransaction(
276 InstanceIdentifier<U> readIID, LogicalDatastoreType logicalDatastoreType) {
277 final ListenableFuture<Optional<U>> readFuture;
278 try (ReadTransaction readTx = txChain.newReadOnlyTransaction()) {
279 readFuture = readTx.read(logicalDatastoreType, readIID);
282 Optional<U> optionalDataObject = readFuture.get();
283 if (optionalDataObject != null && optionalDataObject.isPresent()) {
284 return optionalDataObject.get();
286 LOG.debug("{}: Failed to read", Thread.currentThread().getStackTrace()[1]);
288 } catch (InterruptedException | ExecutionException e) {
289 LOG.warn("Failed to ....", e);
294 private <U extends org.opendaylight.yangtools.yang.binding.DataObject> void deleteTransaction(
295 InstanceIdentifier<U> deleteIID, LogicalDatastoreType logicalDatastoreType, String errMsg) {
297 WriteTransaction writeTx = txChain.newWriteOnlyTransaction();
298 writeTx.delete(logicalDatastoreType, deleteIID);
299 writeTx.commit().addCallback(new FutureCallback<CommitInfo>() {
301 public void onSuccess(CommitInfo result) {
305 public void onFailure(Throwable throwable) {
306 LOG.error("Transaction failed:", throwable);
308 }, MoreExecutors.directExecutor());
312 public void onTransactionChainFailed(TransactionChain chain, Transaction transaction, Throwable cause) {
313 LOG.error("Broken chain {} in DataStoreBackEnd, transaction {}, cause {}", chain, transaction.getIdentifier(),
318 public void onTransactionChainSuccessful(TransactionChain chain) {
319 LOG.info("DataStoreBackEnd closed successfully, chain {}", chain);
322 public void closeTransactionChain() {
323 LOG.debug("Closing DataStoreBackEnd transaction chain...");