Create Version File in Datanode. Contributed by Bharat Viswanadham.

This commit is contained in:
Bharat Viswanadham 2018-06-04 15:28:19 -07:00
parent 79b298111f
commit f26d3466d7
14 changed files with 688 additions and 14 deletions

View File

@ -29,6 +29,8 @@ public final class OzoneConsts {
public static final String STORAGE_DIR = "scm";
public static final String SCM_ID = "scmUuid";
public static final String LAYOUTVERSION = "layOutVersion";
public static final String CTIME = "ctime";
public static final String OZONE_SIMPLE_ROOT_USER = "root";
public static final String OZONE_SIMPLE_HDFS_USER = "hdfs";

View File

@ -45,8 +45,10 @@
public abstract class Storage {
private static final Logger LOG = LoggerFactory.getLogger(Storage.class);
protected static final String STORAGE_DIR_CURRENT = "current";
protected static final String STORAGE_FILE_VERSION = "VERSION";
public static final String STORAGE_DIR_CURRENT = "current";
public static final String STORAGE_FILE_VERSION = "VERSION";
public static final String STORAGE_DIR_HDDS = "hdds";
private final NodeType nodeType;
private final File root;

View File

@ -0,0 +1,80 @@
/**
* 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;
/**
* Datanode layout version which describes information about the layout version
* on the datanode.
*/
public final class DataNodeLayoutVersion {
// We will just be normal and use positive counting numbers for versions.
private final static DataNodeLayoutVersion[] VERSION_INFOS =
{new DataNodeLayoutVersion(1, "HDDS Datanode LayOut Version 1")};
private final String description;
private final int version;
/**
* Never created outside this class.
*
* @param description -- description
* @param version -- version number
*/
private DataNodeLayoutVersion(int version, String description) {
this.description = description;
this.version = version;
}
/**
* Returns all versions.
*
* @return Version info array.
*/
public static DataNodeLayoutVersion[] getAllVersions() {
return VERSION_INFOS.clone();
}
/**
* Returns the latest version.
*
* @return versionInfo
*/
public static DataNodeLayoutVersion getLatestVersion() {
return VERSION_INFOS[VERSION_INFOS.length - 1];
}
/**
* Return description.
*
* @return String
*/
public String getDescription() {
return description;
}
/**
* Return the version.
*
* @return int.
*/
public int getVersion() {
return version;
}
}

View File

@ -0,0 +1,172 @@
/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.helpers;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hdfs.server.datanode.StorageLocation;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.common.InconsistentStorageStateException;
import org.apache.hadoop.ozone.common.Storage;
import org.apache.hadoop.ozone.container.common.DataNodeLayoutVersion;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Properties;
/**
* This is a utility class which helps to create the version file on datanode
* and also validate the content of the version file.
*/
public class DatanodeVersionFile {
private final String scmUuid;
private final long cTime;
private final int layOutVersion;
public DatanodeVersionFile(String scmUuid, long cTime, int layOutVersion) {
this.scmUuid = scmUuid;
this.cTime = cTime;
this.layOutVersion = layOutVersion;
}
private Properties createProperties() {
Properties properties = new Properties();
properties.setProperty(OzoneConsts.SCM_ID, scmUuid);
properties.setProperty(OzoneConsts.CTIME, String.valueOf(cTime));
properties.setProperty(OzoneConsts.LAYOUTVERSION, String.valueOf(
layOutVersion));
return properties;
}
/**
* Creates a version File in specified path.
* @param path
* @throws IOException
*/
public void createVersionFile(File path) throws
IOException {
try (RandomAccessFile file = new RandomAccessFile(path, "rws");
FileOutputStream out = new FileOutputStream(file.getFD())) {
file.getChannel().truncate(0);
Properties properties = createProperties();
/*
* If server is interrupted before this line,
* the version file will remain unchanged.
*/
properties.store(out, null);
/*
* Now the new fields are flushed to the head of the file, but file
* length can still be larger then required and therefore the file can
* contain whole or corrupted fields from its old contents in the end.
* If server is interrupted here and restarted later these extra fields
* either should not effect server behavior or should be handled
* by the server correctly.
*/
file.getChannel().truncate(file.getChannel().size());
}
}
/**
* Creates a property object from the specified file content.
* @param versionFile
* @return Properties
* @throws IOException
*/
public static Properties readFrom(File versionFile) throws IOException {
try (RandomAccessFile file = new RandomAccessFile(versionFile, "rws");
FileInputStream in = new FileInputStream(file.getFD())) {
Properties props = new Properties();
props.load(in);
return props;
}
}
/**
* Verifies scmUuid is valid or not.
* @param scmIdVersionFile
* @param scmId
* @throws InconsistentStorageStateException
*/
@VisibleForTesting
public static void verifyScmUuid(String scmIdVersionFile, String scmId) throws
InconsistentStorageStateException {
Preconditions.checkState(StringUtils.isNotBlank(scmIdVersionFile),
"Invalid scmUuid from Version File.");
Preconditions.checkState(StringUtils.isNotBlank(scmId),
"Invalid scmUuid from SCM version request response");
if(!scmIdVersionFile.equals(scmId)) {
throw new InconsistentStorageStateException("MisMatch of ScmUuid " +
"scmUuid from version File is: " + scmIdVersionFile + "SCM " +
"version response scmUuid is" + scmId);
}
}
/**
* Verifies creationTime is valid or not.
* @param creationTime
*/
@VisibleForTesting
public static void verifyCreationTime(String creationTime) {
Preconditions.checkState(!StringUtils.isBlank(creationTime),
"Invalid creation Time.");
}
/**
* Verifies layOutVersion is valid or not.
* @param lv
* @throws InconsistentStorageStateException
*/
@VisibleForTesting
public static void verifyLayOutVersion(String lv) throws
InconsistentStorageStateException {
Preconditions.checkState(!StringUtils.isBlank(lv),
"Invalid layOutVersion.");
int version = Integer.parseInt(lv);
if(DataNodeLayoutVersion.getLatestVersion().getVersion() != version) {
throw new InconsistentStorageStateException("Incorrect layOutVersion");
}
}
/**
* Returns the versionFile path for the StorageLocation.
* @param location
* @param scmUuid
* @return versionFile - File
*/
@VisibleForTesting
public static File getVersionFile(StorageLocation location, String scmUuid) {
if (location != null) {
String path = location.getUri().getPath();
File parentPath = new File(path + File.separator + Storage
.STORAGE_DIR_HDDS + File.separator + scmUuid + File.separator +
Storage.STORAGE_DIR_CURRENT + File.separator);
File versionFile = new File(parentPath, Storage.STORAGE_FILE_VERSION);
return versionFile;
} else {
return null;
}
}
}

View File

@ -95,7 +95,8 @@ public void execute(ExecutorService executor) {
getEndPointTask(EndpointStateMachine endpoint) {
switch (endpoint.getState()) {
case GETVERSION:
return new VersionEndpointTask(endpoint, conf);
return new VersionEndpointTask(endpoint, conf, context.getParent().
getContainer());
case REGISTER:
return RegisterEndpointTask.newBuilder()
.setConfig(conf)

View File

@ -16,14 +16,30 @@
*/
package org.apache.hadoop.ozone.container.common.states.endpoint;
import com.google.common.base.Preconditions;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hdds.protocol.proto
.StorageContainerDatanodeProtocolProtos.SCMVersionResponseProto;
import org.apache.hadoop.hdfs.server.datanode.StorageLocation;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.common.InconsistentStorageStateException;
import org.apache.hadoop.ozone.common.Storage;
import org.apache.hadoop.ozone.container.common.DataNodeLayoutVersion;
import org.apache.hadoop.ozone.container.common.helpers.DatanodeVersionFile;
import org.apache.hadoop.ozone.container.common.statemachine
.EndpointStateMachine;
import org.apache.hadoop.ozone.container.ozoneimpl.OzoneContainer;
import org.apache.hadoop.ozone.protocol.VersionResponse;
import org.apache.hadoop.util.Time;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Callable;
/**
@ -33,11 +49,15 @@ public class VersionEndpointTask implements
Callable<EndpointStateMachine.EndPointStates> {
private final EndpointStateMachine rpcEndPoint;
private final Configuration configuration;
private final OzoneContainer datanodeContainerManager;
static final Logger LOG =
LoggerFactory.getLogger(VersionEndpointTask.class);
public VersionEndpointTask(EndpointStateMachine rpcEndPoint,
Configuration conf) {
Configuration conf, OzoneContainer container) {
this.rpcEndPoint = rpcEndPoint;
this.configuration = conf;
this.datanodeContainerManager = container;
}
/**
@ -49,15 +69,56 @@ public VersionEndpointTask(EndpointStateMachine rpcEndPoint,
@Override
public EndpointStateMachine.EndPointStates call() throws Exception {
rpcEndPoint.lock();
try{
try {
SCMVersionResponseProto versionResponse =
rpcEndPoint.getEndPoint().getVersion(null);
rpcEndPoint.setVersion(VersionResponse.getFromProtobuf(versionResponse));
VersionResponse response = VersionResponse.getFromProtobuf(
versionResponse);
String scmUuid = response.getValue(OzoneConsts.SCM_ID);
Preconditions.checkState(!StringUtils.isBlank(scmUuid),
"Invalid SCM UuiD in the response.");
EndpointStateMachine.EndPointStates nextState =
rpcEndPoint.getState().getNextState();
rpcEndPoint.setVersion(response);
LOG.debug("scmUuid is {}", scmUuid);
List<StorageLocation> locations = datanodeContainerManager.getLocations();
for (StorageLocation location : locations) {
String path = location.getUri().getPath();
File parentPath = new File(path + File.separator + Storage
.STORAGE_DIR_HDDS + File.separator + scmUuid + File.separator +
Storage.STORAGE_DIR_CURRENT);
File versionFile = DatanodeVersionFile.getVersionFile(location,
scmUuid);
if (!parentPath.exists() && !parentPath.mkdirs()) {
LOG.error("Directory doesn't exist and cannot be created. Path: {}",
parentPath.toString());
rpcEndPoint.setState(EndpointStateMachine.EndPointStates.SHUTDOWN);
throw new IllegalArgumentException("Directory doesn't exist and " +
"cannot be created. " + parentPath.toString());
} else {
if (versionFile.exists()) {
Properties properties = DatanodeVersionFile.readFrom(versionFile);
DatanodeVersionFile.verifyScmUuid(properties.getProperty(
OzoneConsts.SCM_ID), scmUuid);
DatanodeVersionFile.verifyCreationTime(properties.getProperty(
OzoneConsts.CTIME));
DatanodeVersionFile.verifyLayOutVersion(properties.getProperty(
OzoneConsts.LAYOUTVERSION));
} else {
DatanodeVersionFile dnVersionFile = new DatanodeVersionFile(scmUuid,
Time.now(), DataNodeLayoutVersion.getLatestVersion()
.getVersion());
dnVersionFile.createVersionFile(versionFile);
}
}
}
EndpointStateMachine.EndPointStates nextState = rpcEndPoint.getState().
getNextState();
rpcEndPoint.setState(nextState);
rpcEndPoint.zeroMissedCount();
} catch (InconsistentStorageStateException ex) {
throw ex;
} catch (IOException ex) {
rpcEndPoint.logIfNeeded(ex);
} finally {

View File

@ -51,6 +51,7 @@
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@ -82,6 +83,7 @@ public class OzoneContainer {
private final ChunkManager chunkManager;
private final KeyManager keyManager;
private final BlockDeletingService blockDeletingService;
private final List<StorageLocation> locations;
/**
* Creates a network endpoint and enables Ozone container.
@ -93,7 +95,7 @@ public OzoneContainer(
DatanodeDetails datanodeDetails, Configuration ozoneConfig)
throws IOException {
this.ozoneConfig = ozoneConfig;
List<StorageLocation> locations = new LinkedList<>();
locations = new LinkedList<>();
String[] paths = ozoneConfig.getStrings(
OzoneConfigKeys.OZONE_METADATA_DIRS);
if (paths != null && paths.length > 0) {
@ -137,6 +139,10 @@ public OzoneContainer(
};
}
public List<StorageLocation> getLocations() {
return Collections.unmodifiableList(this.locations);
}
/**
* Starts serving requests to ozone container.
*

View File

@ -88,6 +88,10 @@ public void put(String key, String value) {
values.put(key, value);
}
public String getValue(String key) {
return this.values.get(key);
}
/**
* Return a protobuf message.
* @return SCMVersionResponseProto.

View File

@ -57,6 +57,28 @@ public class ScmTestMock implements StorageContainerDatanodeProtocol {
private Map<DatanodeDetails, Map<String, ContainerInfo>> nodeContainers =
new HashMap();
private Map<DatanodeDetails, NodeReportProto> nodeReports = new HashMap<>();
private UUID scmUuid;
public ScmTestMock() {
scmUuid = UUID.randomUUID();
}
/**
* Return scmUuid.
* @return UUID
*/
public UUID getScmUuid() {
return scmUuid;
}
/**
* set scmUuid.
* @param id
*/
public void setSCMUuid(UUID id) {
this.scmUuid = id;
}
/**
* Returns the number of heartbeats made to this class.
*
@ -147,9 +169,11 @@ public long getBytesUsed() {
rpcCount.incrementAndGet();
sleepIfNeeded();
VersionInfo versionInfo = VersionInfo.getLatestVersion();
return VersionResponse.newBuilder()
.setVersion(versionInfo.getVersion())
.addValue(VersionInfo.DESCRIPTION_KEY, versionInfo.getDescription())
.addValue("scmUuid", scmUuid.toString())
.build().getProtobufMessage();
}

View File

@ -0,0 +1,38 @@
/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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;
import org.junit.Assert;
import org.junit.Test;
/**
* This class tests DatanodeLayOutVersion.
*/
public class TestDatanodeLayOutVersion {
@Test
public void testDatanodeLayOutVersion() {
// Check Latest Version and description
Assert.assertEquals(1, DataNodeLayoutVersion.getLatestVersion()
.getVersion());
Assert.assertEquals("HDDS Datanode LayOut Version 1", DataNodeLayoutVersion
.getLatestVersion().getDescription());
Assert.assertEquals(DataNodeLayoutVersion.getAllVersions().length,
DataNodeLayoutVersion.getAllVersions().length);
}
}

View File

@ -19,6 +19,7 @@
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.hdds.scm.ScmConfigKeys;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.ipc.RPC;
@ -145,7 +146,7 @@ public void tearDown() throws Exception {
} catch (Exception e) {
//ignore all execption from the shutdown
} finally {
testRoot.delete();
FileUtil.fullyDelete(testRoot);
}
}

View File

@ -0,0 +1,120 @@
/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.helpers;
import org.apache.hadoop.hdfs.server.datanode.StorageLocation;
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.test.GenericTestUtils;
import org.apache.hadoop.util.Time;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import java.util.UUID;
import static org.junit.Assert.*;
/**
* This class tests DatanodeVersionFile.
*/
public class TestDatanodeVersionFile {
@Rule
public TemporaryFolder folder= new TemporaryFolder();
@Test
public void testCreateAndReadVersionFile() throws IOException{
File versionFile = folder.newFile("Version");
String uuid = UUID.randomUUID().toString();
long now = Time.now();
int lv = DataNodeLayoutVersion.getLatestVersion().getVersion();
DatanodeVersionFile dnVersionFile = new DatanodeVersionFile(uuid, now, lv);
dnVersionFile.createVersionFile(versionFile);
//Check VersionFile exists
assertTrue(versionFile.exists());
Properties properties = dnVersionFile.readFrom(versionFile);
assertEquals(uuid, properties.getProperty(OzoneConsts.SCM_ID));
assertEquals(String.valueOf(now), properties.get(OzoneConsts.CTIME));
assertEquals(String.valueOf(lv), properties.get(OzoneConsts.LAYOUTVERSION));
DatanodeVersionFile.verifyCreationTime(String.valueOf(properties.get(
OzoneConsts.CTIME)));
DatanodeVersionFile.verifyLayOutVersion(String.valueOf(properties
.getProperty(OzoneConsts.LAYOUTVERSION)));
DatanodeVersionFile.verifyScmUuid(uuid, String.valueOf(properties
.getProperty(OzoneConsts.SCM_ID)));
}
@Test
public void testVerifyUuid() throws IOException{
String uuid = UUID.randomUUID().toString();
try {
DatanodeVersionFile.verifyScmUuid(uuid, uuid);
DatanodeVersionFile.verifyScmUuid(uuid, UUID.randomUUID().toString());
fail("Test failure in testVerifyUuid");
} catch (InconsistentStorageStateException ex) {
GenericTestUtils.assertExceptionContains("MisMatch of ScmUuid", ex);
}
}
@Test
public void testVerifyCTime() throws IOException{
try {
DatanodeVersionFile.verifyCreationTime(String.valueOf(Time.now()));
DatanodeVersionFile.verifyCreationTime(null);
fail("Test failure in testVerifyCTime");
} catch (IllegalStateException ex) {
GenericTestUtils.assertExceptionContains("Invalid creation Time.", ex);
}
}
@Test
public void testVerifyLayOut() throws IOException{
String lv = String.valueOf(DataNodeLayoutVersion.getLatestVersion()
.getVersion());
try {
DatanodeVersionFile.verifyLayOutVersion(lv);
DatanodeVersionFile.verifyLayOutVersion(null);
fail("Test failure in testVerifyLayOut");
} catch (IllegalStateException ex) {
GenericTestUtils.assertExceptionContains("Invalid layOutVersion.", ex);
}
}
@Test
public void testGetVersionFile() throws IOException {
StorageLocation location = StorageLocation.parse("/tmp/disk1");
String scmId = UUID.randomUUID().toString();
assertEquals(new File("/tmp/disk1/hdds/" + scmId + "/current/VERSION"),
DatanodeVersionFile.getVersionFile(location, scmId));
assertEquals(null, DatanodeVersionFile.getVersionFile(null, scmId));
}
}

View File

@ -40,6 +40,7 @@
.StorageContainerDatanodeProtocolProtos.SCMVersionRequestProto;
import org.apache.hadoop.ipc.Server;
import org.apache.hadoop.metrics2.util.MBeans;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.protocol.StorageContainerNodeProtocol;
import org.apache.hadoop.ozone.protocol.VersionResponse;
import org.apache.hadoop.ozone.protocol.commands.RegisteredCommand;
@ -703,6 +704,7 @@ long getLastHBProcessedCount() {
public VersionResponse getVersion(SCMVersionRequestProto versionRequest) {
return VersionResponse.newBuilder()
.setVersion(this.version.getVersion())
.addValue(OzoneConsts.SCM_ID, scmManager.getScmStorage().getScmId())
.build();
}

View File

@ -19,6 +19,7 @@
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystemTestHelper;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos;
import org.apache.hadoop.hdds.scm.TestUtils;
@ -33,6 +34,7 @@
.StorageContainerDatanodeProtocolProtos.SCMHeartbeatResponseProto;
import org.apache.hadoop.hdds.protocol.proto
.StorageContainerDatanodeProtocolProtos.SCMRegisteredResponseProto;
import org.apache.hadoop.hdfs.server.datanode.StorageLocation;
import org.apache.hadoop.hdds.protocol.proto
.StorageContainerDatanodeProtocolProtos.StorageReportProto;
import org.apache.hadoop.hdds.protocol.proto
@ -41,6 +43,7 @@
import org.apache.hadoop.ozone.OzoneConfigKeys;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.container.common.helpers.ContainerReport;
import org.apache.hadoop.ozone.container.common.helpers.DatanodeVersionFile;
import org.apache.hadoop.ozone.container.common.statemachine
.DatanodeStateMachine;
import org.apache.hadoop.ozone.container.common.statemachine
@ -53,17 +56,22 @@
import org.apache.hadoop.ozone.container.common.states.endpoint
.VersionEndpointTask;
import org.apache.hadoop.ozone.container.ozoneimpl.OzoneContainer;
import org.apache.hadoop.test.GenericTestUtils;
import org.apache.hadoop.test.PathUtils;
import org.apache.hadoop.util.Time;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import java.io.File;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
import static org.apache.hadoop.hdds.scm.TestUtils.getDatanodeDetails;
@ -116,6 +124,11 @@ public void testGetVersion() throws Exception {
responseProto.getKeys(0).getKey());
Assert.assertEquals(VersionInfo.getLatestVersion().getDescription(),
responseProto.getKeys(0).getValue());
Assert.assertEquals("scmUuid", responseProto.getKeys(
1).getKey());
Assert.assertEquals(scmServerImpl.getScmUuid().toString(),
responseProto.getKeys(1).getValue());
}
}
@ -126,11 +139,20 @@ public void testGetVersion() throws Exception {
*/
public void testGetVersionTask() throws Exception {
Configuration conf = SCMTestUtils.getConf();
String path = new FileSystemTestHelper().getTestRootDir();
conf.set(DFS_DATANODE_DATA_DIR_KEY, path);
try (EndpointStateMachine rpcEndPoint = createEndpoint(conf,
serverAddress, 1000)) {
rpcEndPoint.setState(EndpointStateMachine.EndPointStates.GETVERSION);
OzoneContainer ozoneContainer = mock(OzoneContainer.class);
List<StorageLocation> pathList = new ArrayList<>();
for (String dir : conf.getStrings(DFS_DATANODE_DATA_DIR_KEY)) {
StorageLocation location = StorageLocation.parse(dir);
pathList.add(location);
}
when(ozoneContainer.getLocations()).thenReturn(pathList);
VersionEndpointTask versionTask = new VersionEndpointTask(rpcEndPoint,
conf);
conf, ozoneContainer);
EndpointStateMachine.EndPointStates newState = versionTask.call();
// if version call worked the endpoint should automatically move to the
@ -140,9 +162,131 @@ public void testGetVersionTask() throws Exception {
// Now rpcEndpoint should remember the version it got from SCM
Assert.assertNotNull(rpcEndPoint.getVersion());
FileUtil.fullyDelete(new File(path));
}
}
@Test
public void testVersionCheckFail() throws Exception {
Configuration conf = SCMTestUtils.getConf();
String path = new FileSystemTestHelper().getTestRootDir();
conf.set(DFS_DATANODE_DATA_DIR_KEY, path);
try (EndpointStateMachine rpcEndPoint = createEndpoint(conf,
serverAddress, 1000)) {
rpcEndPoint.setState(EndpointStateMachine.EndPointStates.GETVERSION);
OzoneContainer ozoneContainer = mock(OzoneContainer.class);
List<StorageLocation> pathList = new ArrayList<>();
for (String dir : conf.getStrings(DFS_DATANODE_DATA_DIR_KEY)) {
StorageLocation location = StorageLocation.parse(dir);
pathList.add(location);
}
when(ozoneContainer.getLocations()).thenReturn(pathList);
VersionEndpointTask versionTask = new VersionEndpointTask(rpcEndPoint,
conf, ozoneContainer);
EndpointStateMachine.EndPointStates newState = versionTask.call();
// if version call worked the endpoint should automatically move to the
// next state.
Assert.assertEquals(EndpointStateMachine.EndPointStates.REGISTER,
newState);
// Now rpcEndpoint should remember the version it got from SCM
Assert.assertNotNull(rpcEndPoint.getVersion());
// Now call again version task with an incorrect layout version.
// This will fail with Incorrect layOutVersion error.
DatanodeVersionFile datanodeVersionFile = new DatanodeVersionFile(
scmServerImpl.getScmUuid().toString(), Time.now(), 2);
datanodeVersionFile.createVersionFile(DatanodeVersionFile
.getVersionFile(pathList.get(0), scmServerImpl.getScmUuid()
.toString()));
rpcEndPoint.setState(EndpointStateMachine.EndPointStates.GETVERSION);
versionTask.call();
fail("Test fail");
} catch(Throwable t) {
GenericTestUtils.assertExceptionContains("Incorrect layOutVersion", t);
FileUtil.fullyDelete(new File(path));
}
}
@Test
public void testVersionCheckSuccess() throws Exception {
Configuration conf = SCMTestUtils.getConf();
String path = new FileSystemTestHelper().getTestRootDir();
conf.set(DFS_DATANODE_DATA_DIR_KEY, path);
try (EndpointStateMachine rpcEndPoint = createEndpoint(conf,
serverAddress, 1000)) {
rpcEndPoint.setState(EndpointStateMachine.EndPointStates.GETVERSION);
OzoneContainer ozoneContainer = mock(OzoneContainer.class);
List<StorageLocation> pathList = new ArrayList<>();
for (String dir : conf.getStrings(DFS_DATANODE_DATA_DIR_KEY)) {
StorageLocation location = StorageLocation.parse(dir);
pathList.add(location);
}
when(ozoneContainer.getLocations()).thenReturn(pathList);
VersionEndpointTask versionTask = new VersionEndpointTask(rpcEndPoint,
conf, ozoneContainer);
EndpointStateMachine.EndPointStates newState = versionTask.call();
// if version call worked the endpoint should automatically move to the
// next state.
Assert.assertEquals(EndpointStateMachine.EndPointStates.REGISTER,
newState);
// Now rpcEndpoint should remember the version it got from SCM
Assert.assertNotNull(rpcEndPoint.getVersion());
// Now call again Version Task, this time version check should succeed.
rpcEndPoint.setState(EndpointStateMachine.EndPointStates.GETVERSION);
newState = versionTask.call();
Assert.assertEquals(EndpointStateMachine.EndPointStates.REGISTER,
newState);
FileUtil.fullyDelete(new File(path));
}
}
@Test
public void testVersionCheckFile() throws Exception {
Configuration conf = SCMTestUtils.getConf();
FileUtil.fullyDelete(new File("/tmp/hadoop"));
conf.set(DFS_DATANODE_DATA_DIR_KEY, "/tmp/hadoop");
try (EndpointStateMachine rpcEndPoint = createEndpoint(conf,
serverAddress, 1000)) {
rpcEndPoint.setState(EndpointStateMachine.EndPointStates.GETVERSION);
OzoneContainer ozoneContainer = mock(OzoneContainer.class);
List<StorageLocation> pathList = new ArrayList<>();
String dir = conf.get(DFS_DATANODE_DATA_DIR_KEY);
StorageLocation location = StorageLocation.parse(dir);
pathList.add(location);
when(ozoneContainer.getLocations()).thenReturn(pathList);
VersionEndpointTask versionTask = new VersionEndpointTask(rpcEndPoint,
conf, ozoneContainer);
EndpointStateMachine.EndPointStates newState = versionTask.call();
// if version call worked the endpoint should automatically move to the
// next state.
Assert.assertEquals(EndpointStateMachine.EndPointStates.REGISTER,
newState);
// Now rpcEndpoint should remember the version it got from SCM
Assert.assertNotNull(rpcEndPoint.getVersion());
// Check Version File created or not and content is expected or not.
File versionFile = DatanodeVersionFile.getVersionFile(pathList.get(0),
scmServerImpl.getScmUuid().toString());
Assert.assertTrue(versionFile.exists());
Properties props = DatanodeVersionFile.readFrom(versionFile);
DatanodeVersionFile.verifyCreationTime(props.getProperty(OzoneConsts
.CTIME));
DatanodeVersionFile.verifyScmUuid(scmServerImpl.getScmUuid().toString(),
props.getProperty(OzoneConsts.SCM_ID));
DatanodeVersionFile.verifyLayOutVersion(props.getProperty(OzoneConsts
.LAYOUTVERSION));
}
}
@Test
/**
* This test makes a call to end point where there is no SCM server. We
@ -152,11 +296,20 @@ public void testGetVersionToInvalidEndpoint() throws Exception {
Configuration conf = SCMTestUtils.getConf();
InetSocketAddress nonExistentServerAddress = SCMTestUtils
.getReuseableAddress();
FileUtil.fullyDelete(new File("/tmp/hadoop"));
conf.set(DFS_DATANODE_DATA_DIR_KEY, "/tmp/hadoop");
try (EndpointStateMachine rpcEndPoint = createEndpoint(conf,
nonExistentServerAddress, 1000)) {
rpcEndPoint.setState(EndpointStateMachine.EndPointStates.GETVERSION);
OzoneContainer ozoneContainer = mock(OzoneContainer.class);
List<StorageLocation> pathList = new ArrayList<>();
for (String dir : conf.getStrings(DFS_DATANODE_DATA_DIR_KEY)) {
StorageLocation location = StorageLocation.parse(dir);
pathList.add(location);
}
when(ozoneContainer.getLocations()).thenReturn(pathList);
VersionEndpointTask versionTask = new VersionEndpointTask(rpcEndPoint,
conf);
conf, ozoneContainer);
EndpointStateMachine.EndPointStates newState = versionTask.call();
// This version call did NOT work, so endpoint should remain in the same
@ -176,12 +329,20 @@ public void testGetVersionAssertRpcTimeOut() throws Exception {
final long rpcTimeout = 1000;
final long tolerance = 100;
Configuration conf = SCMTestUtils.getConf();
FileUtil.fullyDelete(new File("/tmp/hadoop"));
conf.set(DFS_DATANODE_DATA_DIR_KEY, "/tmp/hadoop");
try (EndpointStateMachine rpcEndPoint = createEndpoint(conf,
serverAddress, (int) rpcTimeout)) {
rpcEndPoint.setState(EndpointStateMachine.EndPointStates.GETVERSION);
OzoneContainer ozoneContainer = mock(OzoneContainer.class);
List<StorageLocation> pathList = new ArrayList<>();
for (String dir : conf.getStrings(DFS_DATANODE_DATA_DIR_KEY)) {
StorageLocation location = StorageLocation.parse(dir);
pathList.add(location);
}
when(ozoneContainer.getLocations()).thenReturn(pathList);
VersionEndpointTask versionTask = new VersionEndpointTask(rpcEndPoint,
conf);
conf, ozoneContainer);
scmServerImpl.setRpcResponseDelay(1500);
long start = Time.monotonicNow();