/*
* Copyright (c) 2014 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.coordinator.client.model;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.emc.storageos.coordinator.client.model.Constants.*;
public final class SoftwareVersionMetadata {
private static final Logger log = LoggerFactory.getLogger(SoftwareVersionMetadata.class);
private static String IMAGE_FILE_PATH_TEMPLATE = "/.volumes/bootfs/%s/rootimg";
// Suppress Sonar violation of Lazy initialization of static fields should be synchronized
// This method is only used in test case, safe to suppress
@SuppressWarnings("squid:S2444")
public static void setimageFileTemplate(String template) {
IMAGE_FILE_PATH_TEMPLATE = template;
}
private static final String READ_ONLY_ACCESS_MODE = "r";
private static final int VERSION_METADATA_LENGTH = 20480;
private static final String DOWNGRADE_TO_TAG = "downgrade_to:";
private static final String UPGRADE_FROM_TAG = "upgrade_from:";
public SoftwareVersion version;
public List<SoftwareVersion> upgradeFromVersionsList;
public List<SoftwareVersion> downgradeToVersionsList;
private SoftwareVersionMetadata(SoftwareVersion c, List<SoftwareVersion> uL, List<SoftwareVersion> dL) {
version = c;
upgradeFromVersionsList = uL;
downgradeToVersionsList = dL;
}
public static SoftwareVersionMetadata getInstance(SoftwareVersion v) throws IOException {
List<SoftwareVersion> upgradeFromList = new ArrayList<SoftwareVersion>();
List<SoftwareVersion> downgradeToList = new ArrayList<SoftwareVersion>();
String viprMetadataString = readFile(v);
for (String s : viprMetadataString.split("\n")) {
// The metadata file contains multiple lines of properties
if (s.startsWith(UPGRADE_FROM_TAG) && !s.trim().endsWith(":")) {
for (String versionStr : s.substring(UPGRADE_FROM_TAG.length()).split(",")) {
upgradeFromList.add(new SoftwareVersion(versionStr));
}
}
if (s.startsWith(DOWNGRADE_TO_TAG) && !s.trim().endsWith(":")) {
for (String versionStr : s.substring(DOWNGRADE_TO_TAG.length()).split(",")) {
downgradeToList.add(new SoftwareVersion(versionStr));
}
}
}
return new SoftwareVersionMetadata(v, upgradeFromList, downgradeToList);
}
private static String readFile(SoftwareVersion v) throws IOException {
String imageFilePath = String.format(IMAGE_FILE_PATH_TEMPLATE, v.toString());
File f = new File(imageFilePath);
long size = f.length();
RandomAccessFile file = null;
try {
file = new RandomAccessFile(f, READ_ONLY_ACCESS_MODE);
} catch (FileNotFoundException e) {
log.error("Image file doesn't exist! Stack trace: ", e);
throw e;
}
byte[] buffer = new byte[VERSION_METADATA_LENGTH];
try {
file.seek(size - TRAILER_LENGTH - VERSION_METADATA_LENGTH); // Skip until the beginning of the version metadata
file.read(buffer, 0, VERSION_METADATA_LENGTH);
} catch (IOException e) {
log.error("IOException while extract upgrade from version info! Stack trace: ", e);
throw e;
} finally {
try {
file.close();
} catch (IOException e) {
log.debug(String.format("IOException is throwed when closing file %s", f.getAbsolutePath()), e);
}
}
String viprMetadataString = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(buffer)).toString();
return viprMetadataString;
}
}