blob: cb356dadeb236360a214d729cd511e29a3047c6c [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.ozone.container.common.utils;
import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.common.InconsistentStorageStateException;
import org.apache.hadoop.ozone.container.common.DataNodeLayoutVersion;
import org.apache.hadoop.ozone.container.common.volume.HddsVolume;
import org.apache.hadoop.util.Time;
import org.slf4j.Logger;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import java.util.UUID;
/**
* A util class for {@link HddsVolume}.
*/
public final class HddsVolumeUtil {
// Private constructor for Utility class. Unused.
private HddsVolumeUtil() {
}
private static final String VERSION_FILE = "VERSION";
private static final String STORAGE_ID_PREFIX = "DS-";
public static File getVersionFile(File rootDir) {
return new File(rootDir, VERSION_FILE);
}
public static String generateUuid() {
return STORAGE_ID_PREFIX + UUID.randomUUID();
}
/**
* Get hddsRoot from volume root. If volumeRoot points to hddsRoot, it is
* returned as is.
* For a volumeRoot /data/disk1, the hddsRoot is /data/disk1/hdds.
* @param volumeRoot root of the volume.
* @return hddsRoot of the volume.
*/
public static String getHddsRoot(String volumeRoot) {
if (volumeRoot.endsWith(HddsVolume.HDDS_VOLUME_DIR)) {
return volumeRoot;
} else {
File hddsRoot = new File(volumeRoot, HddsVolume.HDDS_VOLUME_DIR);
return hddsRoot.getPath();
}
}
/**
* Returns storageID if it is valid. Throws an exception otherwise.
*/
@VisibleForTesting
public static String getStorageID(Properties props, File versionFile)
throws InconsistentStorageStateException {
return getProperty(props, OzoneConsts.STORAGE_ID, versionFile);
}
/**
* Returns clusterID if it is valid. It should match the clusterID from the
* Datanode. Throws an exception otherwise.
*/
@VisibleForTesting
public static String getClusterID(Properties props, File versionFile,
String clusterID) throws InconsistentStorageStateException {
String cid = getProperty(props, OzoneConsts.CLUSTER_ID, versionFile);
if (clusterID == null) {
return cid;
}
if (!clusterID.equals(cid)) {
throw new InconsistentStorageStateException("Mismatched " +
"ClusterIDs. Version File : " + versionFile + " has clusterID: " +
cid + " and Datanode has clusterID: " + clusterID);
}
return cid;
}
/**
* Returns datanodeUuid if it is valid. It should match the UUID of the
* Datanode. Throws an exception otherwise.
*/
@VisibleForTesting
public static String getDatanodeUUID(Properties props, File versionFile,
String datanodeUuid)
throws InconsistentStorageStateException {
String datanodeID = getProperty(props, OzoneConsts.DATANODE_UUID,
versionFile);
if (datanodeUuid != null && !datanodeUuid.equals(datanodeID)) {
throw new InconsistentStorageStateException("Mismatched " +
"DatanodeUUIDs. Version File : " + versionFile + " has datanodeUuid: "
+ datanodeID + " and Datanode has datanodeUuid: " + datanodeUuid);
}
return datanodeID;
}
/**
* Returns creationTime if it is valid. Throws an exception otherwise.
*/
@VisibleForTesting
public static long getCreationTime(Properties props, File versionFile)
throws InconsistentStorageStateException {
String cTimeStr = getProperty(props, OzoneConsts.CTIME, versionFile);
long cTime = Long.parseLong(cTimeStr);
long currentTime = Time.now();
if (cTime > currentTime || cTime < 0) {
throw new InconsistentStorageStateException("Invalid Creation time in " +
"Version File : " + versionFile + " - " + cTime + ". Current system" +
" time is " + currentTime);
}
return cTime;
}
/**
* Returns layOutVersion if it is valid. Throws an exception otherwise.
*/
@VisibleForTesting
public static int getLayOutVersion(Properties props, File versionFile) throws
InconsistentStorageStateException {
String lvStr = getProperty(props, OzoneConsts.LAYOUTVERSION, versionFile);
int lv = Integer.parseInt(lvStr);
if(DataNodeLayoutVersion.getLatestVersion().getVersion() != lv) {
throw new InconsistentStorageStateException("Invalid layOutVersion. " +
"Version file has layOutVersion as " + lv + " and latest Datanode " +
"layOutVersion is " +
DataNodeLayoutVersion.getLatestVersion().getVersion());
}
return lv;
}
private static String getProperty(Properties props, String propName, File
versionFile)
throws InconsistentStorageStateException {
String value = props.getProperty(propName);
if (StringUtils.isBlank(value)) {
throw new InconsistentStorageStateException("Invalid " + propName +
". Version File : " + versionFile + " has null or empty " + propName);
}
return value;
}
/**
* Check Volume is in consistent state or not.
* @param hddsVolume
* @param scmId
* @param clusterId
* @param logger
* @return true - if volume is in consistent state, otherwise false.
*/
public static boolean checkVolume(HddsVolume hddsVolume, String scmId, String
clusterId, Logger logger) {
File hddsRoot = hddsVolume.getHddsRootDir();
String volumeRoot = hddsRoot.getPath();
File scmDir = new File(hddsRoot, scmId);
try {
hddsVolume.format(clusterId);
} catch (IOException ex) {
logger.error("Error during formatting volume {}, exception is {}",
volumeRoot, ex);
return false;
}
File[] hddsFiles = hddsRoot.listFiles();
if(hddsFiles == null) {
// This is the case for IOException, where listFiles returns null.
// So, we fail the volume.
return false;
} else if (hddsFiles.length == 1) {
// DN started for first time or this is a newly added volume.
// So we create scm directory.
if (!scmDir.mkdir()) {
logger.error("Unable to create scmDir {}", scmDir);
return false;
}
return true;
} else if(hddsFiles.length == 2) {
// The files should be Version and SCM directory
if (scmDir.exists()) {
return true;
} else {
logger.error("Volume {} is in Inconsistent state, expected scm " +
"directory {} does not exist", volumeRoot, scmDir
.getAbsolutePath());
return false;
}
} else {
// The hdds root dir should always have 2 files. One is Version file
// and other is SCM directory.
return false;
}
}
}