2 * Copyright © 2017 AT&T and others. 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
9 package org.opendaylight.transportpce.inventory.job;
11 import com.fasterxml.jackson.core.JsonProcessingException;
12 import com.fasterxml.jackson.databind.ObjectMapper;
13 import com.google.common.base.Strings;
14 import com.google.common.io.Files;
17 import java.io.IOException;
18 import java.nio.charset.StandardCharsets;
19 import java.text.SimpleDateFormat;
20 import java.util.Date;
21 import java.util.Optional;
22 import java.util.concurrent.ExecutionException;
24 import org.apache.karaf.scheduler.Job;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
29 import org.opendaylight.transportpce.common.InstanceIdentifiers;
30 import org.opendaylight.transportpce.common.Timeouts;
31 import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
32 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.OrgOpenroadmDevice;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
42 * Class which periodically backups the device into a file implements {@link Job}
43 * interface which is automatically registered via whitboard pattern into karaf
44 * environment. This job will persist an {@link OrgOpenroadmDevice} capable with
45 * the models provided in transportpce-models
47 public class PeriodicDeviceBackupJob implements Runnable {
49 private static final String TIMESTAMP_FORMAT = "yyyy-MM-dd_HH-mm-ss-SSS";
50 private static final String ORG_OPENROADM_DEVICE = "org-openroadm-device";
51 private static final Logger LOG = LoggerFactory.getLogger(PeriodicDeviceBackupJob.class);
53 private final DataBroker dataBroker;
54 private final DeviceTransactionManager deviceTransactionManager;
56 private final SchemaContext schemaContext;
57 private final SimpleDateFormat filenameFormatter;
60 * Folder property, where the file is placed.
62 private String folder;
64 * Prefix of device file.
66 private String filePrefix;
69 * Constructor with injected fields.
71 * @param dataBroker the datatabroker
72 * @param domSchemaService the DOM schema service
73 * @param deviceTransactionManager the device transaction manager
75 public PeriodicDeviceBackupJob(DataBroker dataBroker, DOMSchemaService domSchemaService,
76 DeviceTransactionManager deviceTransactionManager) {
77 this.dataBroker = dataBroker;
78 this.schemaContext = domSchemaService.getGlobalContext();
79 this.deviceTransactionManager = deviceTransactionManager;
80 this.filenameFormatter = new SimpleDateFormat(TIMESTAMP_FORMAT);
85 LOG.info("Running periodical device backup into {}", folder);
88 } catch (InterruptedException | ExecutionException e) {
89 LOG.warn("Unable to read netconf topology from the operational datastore", e);
98 public String getFolder() {
105 * @param folder the folder to set
107 public void setFolder(String folder) {
108 this.folder = folder;
112 * Gets the filePrefix.
114 * @return the filePrefix
116 public String getFilePrefix() {
121 * Sets the filePrefix.
123 * @param filePrefix the filePrefix to set
125 public void setFilePrefix(String filePrefix) {
126 this.filePrefix = filePrefix;
130 * Stores all devices into files.
132 * @throws InterruptedException interrupted exception
133 * @throws ExecutionException execution exception
135 private void backupAllDevices() throws InterruptedException, ExecutionException {
136 ReadOnlyTransaction newReadOnlyTransaction = dataBroker.newReadOnlyTransaction();
137 Optional<Topology> topology = newReadOnlyTransaction
138 .read(LogicalDatastoreType.OPERATIONAL, InstanceIdentifiers.NETCONF_TOPOLOGY_II).get().toJavaUtil();
139 if (!topology.isPresent()) {
140 LOG.warn("Netconf topology was not found in datastore");
144 for (Node node : topology.get().getNode()) {
145 String nodeId = getNodeId(node);
146 if (Strings.isNullOrEmpty(nodeId)) {
147 LOG.debug("{} node is not a roadm device");
150 storeRoadmDevice(nodeId);
155 * Stores a single ROADM device into a file.
157 * @param nodeId the node ID
159 private void storeRoadmDevice(String nodeId) {
160 InstanceIdentifier<OrgOpenroadmDevice> deviceIi = InstanceIdentifier.create(OrgOpenroadmDevice.class);
161 Optional<OrgOpenroadmDevice> deviceObject =
162 deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.OPERATIONAL, deviceIi,
163 Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
164 if (!deviceObject.isPresent()) {
165 LOG.warn("Device object {} is not present.", nodeId);
169 // TODO: Serialization should be done via XMLDataObjectConverter when devices use the same model as
172 * XMLDataObjectConverter createWithSchemaContext =
173 * XMLDataObjectConverter.createWithSchemaContext(schemaContext, nodeSerializer); Writer
174 * writerFromDataObject = createWithSchemaContext.writerFromDataObject(deviceObject.get(),
175 * OrgOpenroadmDevice.class, createWithSchemaContext.dataContainer());
177 StringBuilder serializedDevice = new StringBuilder();
179 serializedDevice.append(new ObjectMapper().writeValueAsString(deviceObject.get()));
180 } catch (JsonProcessingException e1) {
181 LOG.error(e1.getMessage(), e1);
184 String prepareFileName = prepareFileName(nodeId);
185 File parent = new File(folder);
186 if (!parent.exists() && !parent.isDirectory() && !parent.mkdirs()) {
187 LOG.error("Could not create empty directory {}", folder);
188 throw new IllegalStateException(String.format("Could not create empty directory %s", folder));
191 File file = new File(parent, filePrefix.concat(prepareFileName));
193 throw new IllegalStateException(String.format("The file %s already exists", file));
196 Files.asCharSink(file, StandardCharsets.UTF_8).write(serializedDevice.toString());
197 } catch (IOException e) {
198 LOG.error("Could not write device backup into file {}", file);
202 private String prepareFileName(String nodeId) {
203 String format = filenameFormatter.format(new Date());
204 StringBuilder sb = new StringBuilder(format);
205 sb.append("__").append(nodeId).append("__").append(".xml");
206 return sb.toString();
210 * If the {@link Node} in the {@link Topology} is a {@link NetconfNode}, has
211 * capabilities of {@link PeriodicDeviceBackupJob#ORG_OPENROADM_DEVICE} and the
212 * key is not null returns the identifier of {@link OrgOpenroadmDevice} node.
214 * @param node inside the {@link Topology}
217 private static String getNodeId(Node node) {
219 LOG.trace("The node is null");
222 NetconfNode netconfNode = node.getAugmentation(NetconfNode.class);
223 if (netconfNode == null) {
224 LOG.trace("The node {} has not properties of NetconfNode", node);
227 if (netconfNode.getAvailableCapabilities() == null
228 || netconfNode.getAvailableCapabilities().getAvailableCapability() == null) {
229 LOG.trace("No available capabilities");
232 long count = netconfNode.getAvailableCapabilities().getAvailableCapability().stream()
233 .filter(cp -> cp.getCapability() != null && cp.getCapability().contains(ORG_OPENROADM_DEVICE)).count();
235 LOG.trace("The node {} has not capabilities of OpenROADMDevice", node);
238 if (node.getKey() == null || node.getKey().getNodeId() == null) {
239 LOG.trace("Node {} has invalid key", node);
242 if ("controller-config".equalsIgnoreCase(node.getKey().getNodeId().getValue())) {
243 LOG.info("Got controller-config instead of roadm-node");
246 return node.getKey().getNodeId().getValue();