/**
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*
* This software contains the intellectual property of EMC Corporation
* or is licensed to EMC Corporation from third parties. Use of this
* software and the intellectual property contained therein is expressly
* limited to the terms and conditions of the License Agreement under which
* it is provided by or on behalf of EMC.
*/
package com.emc.storageos.vplex.api.clientdata.formatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.vplex.api.VPlexApiConstants;
import com.emc.storageos.vplex.api.VPlexApiException;
import com.emc.storageos.vplex.api.clientdata.VolumeInfo;
/**
* This class provides functionality for generating claimed
* volume names formatted to fit within the VPLEX API's
* maximum volume length for distributed volumes of 63
* characters. A single volume name should take up no more
* than half of this space so that a distributed volume name
* consisting of two claimed volume names can be constructed.
*/
public class DefaultVplexVolumeNameFormatter {
// A logger reference.
protected static Logger s_logger = LoggerFactory.getLogger(DefaultVplexVolumeNameFormatter.class);
// the VolumeInfo instance to work with, protected for use in child classes
protected VolumeInfo _volumeInfo;
// the storage system's serial number
protected String _storageSystemSerialNumber;
// the volume's native id
protected String _volumeNativeId;
/**
* Constructor.
*
* @param volumeInfo the VolumeInfo to work with for name formatting
*/
public DefaultVplexVolumeNameFormatter(VolumeInfo volumeInfo) {
this._volumeInfo = volumeInfo;
String storageSystemNativeGuid = _volumeInfo.getStorageSystemNativeGuid();
storageSystemNativeGuid = storageSystemNativeGuid
.replace(VPlexApiConstants.DOT_OPERATOR,
VPlexApiConstants.UNDERSCORE_OPERATOR);
_storageSystemSerialNumber = storageSystemNativeGuid.substring(
storageSystemNativeGuid.indexOf(VPlexApiConstants.PLUS_OPERATOR) + 1);
_volumeNativeId = _volumeInfo.getVolumeNativeId();
}
/**
* Generates a claimed volume name string based on the
* properties of the supplied VolumeInfo object. Can be
* overridden by child classes to return a custom name format
* for a non-default storage system type.
*
* @param volumeInfo the VolumeInfo instance for the claimed volume
* @return a formatted string
*/
public String format() {
s_logger.info("formatting claimed volume name " + _volumeNativeId);
String volumeName = assembleDefaultName(_storageSystemSerialNumber, _volumeNativeId);
if (volumeName.length() <= VPlexApiConstants.MAX_VOL_NAME_LENGTH) {
return volumeName;
} else {
int shortenBy = volumeName.length() - VPlexApiConstants.MAX_VOL_NAME_LENGTH;
return shortenName(shortenBy);
}
}
/**
* Creates a shortened claimed volume name string if the one generated
* by default does not fit within the maximum volume name length. Can be
* overridden by child classes to return a custom shortened name format.
*
* @param volumeInfo the VolumeInfo instance for the claimed volume
* @param shortenBy the number of characters by which to reduce the name's length
* @return a formatted string that has been shortened
* to fit within the maximum volume name length
* @throws VPlexApiException if the name cannot be shortened safely
*/
protected String shortenName(int shortenBy) throws VPlexApiException {
s_logger.info("claimed volume name {} needs to be shortened by {} characters",
_volumeInfo.getVolumeNativeId(),
shortenBy);
// First, lets try shave off some of the front of the storage system serial number
if (_storageSystemSerialNumber.length() > shortenBy) {
return assembleDefaultName(
_storageSystemSerialNumber.substring(shortenBy), _volumeNativeId);
} else if (_volumeNativeId.length() > shortenBy) {
// Second - lets try shave off some of the front of the volume native id
return assembleDefaultName(
_storageSystemSerialNumber, _volumeNativeId.substring(shortenBy));
} else {
// Otherwise - just shorten the combined name
s_logger.warn("The storage system serial number {} and volume native id"
+ "{} is not long enough to be "
+ "used for shortening the volume name by {} characters, so we "
+ "are going to truncate the beginning of the whole name",
_storageSystemSerialNumber, _volumeNativeId, shortenBy);
String volumeName = assembleDefaultName(_storageSystemSerialNumber, _volumeNativeId);
// Just removing beginning of the assembled name may have number in the start
// Safeguard it by adding the "V" to the start again, as VPLEX does not accept virtual
// volume names starting with number
return VPlexApiConstants.VOLUME_NAME_PREFIX + volumeName.substring(shortenBy + 1);
}
}
/**
* Assembles the volume name with the default format of the character
* 'V' plus the storage system serial number plus a hyphen
* plus the volume native id.
*
* @param storageSystemSerialNumber the storage system's serial number
* @param volumeNativeId the volume's native id
* @return the volume name in the default format
*/
protected String assembleDefaultName(String storageSystemSerialNumber, String volumeNativeId) {
StringBuilder nameBuilder = new StringBuilder();
// Note that we need to prepend the prefix because the VPlex does not
// like the claimed storage volume name to start with a number, which
// can be the case for Symmetrix volumes, whose serial numbers start
// with a number.
nameBuilder.append(VPlexApiConstants.VOLUME_NAME_PREFIX);
nameBuilder.append(storageSystemSerialNumber);
nameBuilder.append(VPlexApiConstants.HYPHEN_OPERATOR);
nameBuilder.append(volumeNativeId);
return nameBuilder.toString();
}
}