This is an automated email from the ASF dual-hosted git repository.
sammichen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 74ecb3bde9 HDDS-9245. Add tool for upgrading container layout v2 to v3
(#5539)
74ecb3bde9 is described below
commit 74ecb3bde9c33889f89331d66fa6bd436a0ec471
Author: hao guo <[email protected]>
AuthorDate: Wed Jan 10 21:02:15 2024 +0800
HDDS-9245. Add tool for upgrading container layout v2 to v3 (#5539)
---
.../org/apache/hadoop/ozone/common/Storage.java | 2 +-
.../container/common/utils/DatanodeStoreCache.java | 6 +
.../hdds/scm/cli/container/ContainerCommands.java | 3 +-
.../hdds/scm/cli/container/UpgradeSubcommand.java | 205 +++++++++++++++++
.../scm/cli/container/upgrade/UpgradeChecker.java | 111 +++++++++
.../scm/cli/container/upgrade/UpgradeManager.java | 92 +++-----
.../scm/cli/container/upgrade/UpgradeTask.java | 255 +++++++++++++--------
.../scm/cli/container/upgrade/UpgradeUtils.java | 25 ++
.../cli/container/upgrade/TestUpgradeManager.java | 7 +-
.../shell/TestOzoneContainerUpgradeShell.java | 249 ++++++++++++++++++++
10 files changed, 797 insertions(+), 158 deletions(-)
diff --git
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/common/Storage.java
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/common/Storage.java
index ae291c633f..bc83a6cdf1 100644
---
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/common/Storage.java
+++
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/common/Storage.java
@@ -50,7 +50,7 @@ public abstract class Storage {
private static final Logger LOG = LoggerFactory.getLogger(Storage.class);
public static final String STORAGE_DIR_CURRENT = "current";
- protected static final String STORAGE_FILE_VERSION = "VERSION";
+ public static final String STORAGE_FILE_VERSION = "VERSION";
public static final String CONTAINER_DIR = "containerDir";
private final NodeType nodeType;
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/utils/DatanodeStoreCache.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/utils/DatanodeStoreCache.java
index 7edfcd9969..b0b6f98cbe 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/utils/DatanodeStoreCache.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/utils/DatanodeStoreCache.java
@@ -61,6 +61,12 @@ public final class DatanodeStoreCache {
getInstance().miniClusterMode = true;
}
+ @VisibleForTesting
+ public static synchronized void setMiniClusterMode(boolean isMiniCluster) {
+ getInstance().miniClusterMode = isMiniCluster;
+ }
+
+
public void addDB(String containerDBPath, RawDB db) {
datanodeStoreMap.putIfAbsent(containerDBPath, db);
LOG.info("Added db {} to cache", containerDBPath);
diff --git
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/ContainerCommands.java
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/ContainerCommands.java
index a3d07728eb..54c69273f0 100644
---
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/ContainerCommands.java
+++
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/ContainerCommands.java
@@ -42,7 +42,8 @@ import picocli.CommandLine.Spec;
InfoSubcommand.class,
CreateSubcommand.class,
CloseSubcommand.class,
- ReportSubcommand.class
+ ReportSubcommand.class,
+ UpgradeSubcommand.class
})
@MetaInfServices(SubcommandWithParent.class)
public class ContainerCommands implements Callable<Void>, SubcommandWithParent
{
diff --git
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/UpgradeSubcommand.java
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/UpgradeSubcommand.java
new file mode 100644
index 0000000000..a94f631b5b
--- /dev/null
+++
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/UpgradeSubcommand.java
@@ -0,0 +1,205 @@
+/*
+ * 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.hdds.scm.cli.container;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Strings;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.hadoop.hdds.cli.HddsVersionProvider;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.protocol.DatanodeDetails;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+import org.apache.hadoop.hdds.scm.ScmConfigKeys;
+import org.apache.hadoop.hdds.scm.cli.container.upgrade.UpgradeChecker;
+import org.apache.hadoop.hdds.scm.cli.container.upgrade.UpgradeManager;
+import org.apache.hadoop.hdds.scm.cli.container.upgrade.UpgradeUtils;
+import org.apache.hadoop.hdds.server.OzoneAdmins;
+import org.apache.hadoop.hdds.upgrade.HDDSLayoutFeature;
+import org.apache.hadoop.ozone.common.Storage;
+import org.apache.hadoop.ozone.container.common.volume.HddsVolume;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+
+import java.io.File;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Scanner;
+import java.util.concurrent.Callable;
+
+/**
+ * This is the handler that process container upgrade command.
+ */
+@Command(
+ name = "upgrade",
+ description = "Offline upgrade all schema V2 containers to schema V3 " +
+ "for this datanode.",
+ mixinStandardHelpOptions = true,
+ versionProvider = HddsVersionProvider.class)
+public class UpgradeSubcommand implements Callable<Void> {
+
+ private static final Logger LOG =
+ LoggerFactory.getLogger(UpgradeSubcommand.class);
+
+ @CommandLine.Spec
+ private static CommandLine.Model.CommandSpec spec;
+
+ @CommandLine.Option(names = {"--volume"},
+ required = false,
+ description = "volume path")
+ private String volume;
+
+ @CommandLine.Option(names = {"-y", "--yes"},
+ description = "Continue without interactive user confirmation")
+ private boolean yes;
+
+ private static OzoneConfiguration ozoneConfiguration;
+
+
+ @Override
+ public Void call() throws Exception {
+ OzoneConfiguration configuration = getConfiguration();
+ // Verify admin privilege
+ OzoneAdmins admins = OzoneAdmins.getOzoneAdmins("", configuration);
+ if (!admins.isAdmin(UserGroupInformation.getCurrentUser())) {
+ out().println("It requires ozone administrator privilege. Current user" +
+ " is " + UserGroupInformation.getCurrentUser() + ".");
+ return null;
+ }
+
+ final UpgradeChecker upgradeChecker = new UpgradeChecker();
+ Pair<Boolean, String> pair = upgradeChecker.checkDatanodeRunning();
+ final boolean isRunning = pair.getKey();
+ if (isRunning) {
+ out().println(pair.getValue());
+ return null;
+ }
+
+ DatanodeDetails dnDetail =
+ UpgradeUtils.getDatanodeDetails(configuration);
+
+ Pair<HDDSLayoutFeature, HDDSLayoutFeature> layoutFeature =
+ upgradeChecker.getLayoutFeature(dnDetail, configuration);
+ final HDDSLayoutFeature softwareLayoutFeature = layoutFeature.getLeft();
+ final HDDSLayoutFeature metadataLayoutFeature = layoutFeature.getRight();
+ final int needLayoutVersion =
+ HDDSLayoutFeature.DATANODE_SCHEMA_V3.layoutVersion();
+
+ if (metadataLayoutFeature.layoutVersion() < needLayoutVersion ||
+ softwareLayoutFeature.layoutVersion() < needLayoutVersion) {
+ out().println(String.format(
+ "Please upgrade your software version, no less than %s," +
+ " current metadata layout version is %s," +
+ " software layout version is %s",
+ HDDSLayoutFeature.DATANODE_SCHEMA_V3.name(),
+ metadataLayoutFeature.name(), softwareLayoutFeature.name()));
+ return null;
+ }
+
+ if (!Strings.isNullOrEmpty(volume)) {
+ File volumeDir = new File(volume);
+ if (!volumeDir.exists() || !volumeDir.isDirectory()) {
+ out().println(
+ String.format("Volume path %s is not a directory or doesn't exist",
+ volume));
+ return null;
+ }
+ File hddsRootDir = new File(volume + "/" + HddsVolume.HDDS_VOLUME_DIR);
+ File versionFile = new File(volume + "/" + HddsVolume.HDDS_VOLUME_DIR +
+ "/" + Storage.STORAGE_FILE_VERSION);
+ if (!hddsRootDir.exists() || !hddsRootDir.isDirectory() ||
+ !versionFile.exists() || !versionFile.isFile()) {
+ out().println(
+ String.format("Volume path %s is not a valid data volume",
volume));
+ return null;
+ }
+ configuration.set(ScmConfigKeys.HDDS_DATANODE_DIR_KEY, volume);
+ }
+
+ final HddsProtos.NodeOperationalState opState =
+ dnDetail.getPersistedOpState();
+
+ if (!opState.equals(HddsProtos.NodeOperationalState.IN_MAINTENANCE)) {
+ out().println("This command requires the datanode's " +
+ "NodeOperationalState to be IN_MAINTENANCE, currently is " +
+ opState);
+ return null;
+ }
+
+ List<HddsVolume> allVolume =
+ upgradeChecker.getAllVolume(dnDetail, configuration);
+
+ Iterator<HddsVolume> volumeIterator = allVolume.iterator();
+ while (volumeIterator.hasNext()) {
+ HddsVolume hddsVolume = volumeIterator.next();
+ if (UpgradeChecker.isAlreadyUpgraded(hddsVolume)) {
+ out().println("Volume " + hddsVolume.getVolumeRootDir() +
+ " is already upgraded, skip it.");
+ volumeIterator.remove();
+ }
+ }
+
+ if (allVolume.isEmpty()) {
+ out().println("There is no more volume to upgrade. Exit.");
+ return null;
+ }
+
+ if (!yes) {
+ Scanner scanner = new Scanner(new InputStreamReader(
+ System.in, StandardCharsets.UTF_8));
+ System.out.println(
+ "All volume db stores will be automatically backup," +
+ " should we continue the upgrade ? [yes|no] : ");
+ boolean confirm = scanner.next().trim().equals("yes");
+ scanner.close();
+ if (!confirm) {
+ return null;
+ }
+ }
+
+ // do upgrade
+ final UpgradeManager upgradeManager = new UpgradeManager();
+ upgradeManager.run(configuration, allVolume);
+ return null;
+ }
+
+ @VisibleForTesting
+ public static void setOzoneConfiguration(OzoneConfiguration config) {
+ ozoneConfiguration = config;
+ }
+
+ private OzoneConfiguration getConfiguration() {
+ if (ozoneConfiguration == null) {
+ ozoneConfiguration = new OzoneConfiguration();
+ }
+ return ozoneConfiguration;
+ }
+
+ private static PrintWriter err() {
+ return spec.commandLine().getErr();
+ }
+
+ private static PrintWriter out() {
+ return spec.commandLine().getOut();
+ }
+}
diff --git
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/UpgradeChecker.java
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/UpgradeChecker.java
new file mode 100644
index 0000000000..44516c0687
--- /dev/null
+++
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/UpgradeChecker.java
@@ -0,0 +1,111 @@
+/*
+ * 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.hdds.scm.cli.container.upgrade;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.protocol.DatanodeDetails;
+import org.apache.hadoop.hdds.upgrade.HDDSLayoutFeature;
+import org.apache.hadoop.hdds.upgrade.HDDSLayoutVersionManager;
+import org.apache.hadoop.ozone.container.common.DatanodeLayoutStorage;
+import org.apache.hadoop.ozone.container.common.utils.StorageVolumeUtil;
+import org.apache.hadoop.ozone.container.common.volume.HddsVolume;
+import org.apache.hadoop.ozone.container.common.volume.MutableVolumeSet;
+import org.apache.hadoop.ozone.container.common.volume.StorageVolume;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * This is the handler that process container upgrade checker.
+ */
+public class UpgradeChecker {
+
+ /*
+ * Verify that the datanode is in the shutdown state or running.
+ */
+ public Pair<Boolean, String> checkDatanodeRunning() {
+ String command =
+ "ps aux | grep org.apache.hadoop.ozone.HddsDatanodeService " +
+ "| grep -v grep";
+ try {
+ Process exec = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c",
+ command});
+ boolean notTimeout = exec.waitFor(10, TimeUnit.SECONDS);
+ if (!notTimeout) {
+ return Pair.of(true,
+ String.format("Execution of the command '%s' timeout", command));
+ }
+ if (exec.exitValue() == 0) {
+ return Pair.of(true, "HddsDatanodeService is running." +
+ " This upgrade command requires datanode to be off and in" +
+ " the IN_MAINTENANCE mode. Please put the datanode in" +
+ " the desired state first, then try this command later again.");
+ } else if (exec.exitValue() == 1) {
+ return Pair.of(false, "HddsDatanodeService is not running.");
+ } else {
+ return Pair.of(true,
+ String.format("Return code of the command '%s' is %d", command,
+ exec.exitValue()));
+ }
+ } catch (IOException | InterruptedException e) {
+ return Pair.of(true,
+ String.format("Run command '%s' has error '%s'",
+ command, e.getMessage()));
+ }
+ }
+
+ public Pair<HDDSLayoutFeature, HDDSLayoutFeature> getLayoutFeature(
+ DatanodeDetails dnDetail, OzoneConfiguration conf) throws IOException {
+ DatanodeLayoutStorage layoutStorage =
+ new DatanodeLayoutStorage(conf, dnDetail.getUuidString());
+ HDDSLayoutVersionManager layoutVersionManager =
+ new HDDSLayoutVersionManager(layoutStorage.getLayoutVersion());
+
+ final int metadataLayoutVersion =
+ layoutVersionManager.getMetadataLayoutVersion();
+ final HDDSLayoutFeature metadataLayoutFeature =
+ (HDDSLayoutFeature) layoutVersionManager.getFeature(
+ metadataLayoutVersion);
+
+ final int softwareLayoutVersion =
+ layoutVersionManager.getSoftwareLayoutVersion();
+ final HDDSLayoutFeature softwareLayoutFeature =
+ (HDDSLayoutFeature) layoutVersionManager.getFeature(
+ softwareLayoutVersion);
+
+ return Pair.of(softwareLayoutFeature, metadataLayoutFeature);
+ }
+
+ public List<HddsVolume> getAllVolume(DatanodeDetails detail,
+ OzoneConfiguration configuration) throws IOException {
+ final MutableVolumeSet dataVolumeSet = UpgradeUtils
+ .getHddsVolumes(configuration, StorageVolume.VolumeType.DATA_VOLUME,
+ detail.getUuidString());
+ return
StorageVolumeUtil.getHddsVolumesList(dataVolumeSet.getVolumesList());
+ }
+
+ public static boolean isAlreadyUpgraded(HddsVolume hddsVolume) {
+ final File migrateFile =
+ UpgradeUtils.getVolumeUpgradeCompleteFile(hddsVolume);
+ return migrateFile.exists();
+ }
+}
diff --git
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/UpgradeManager.java
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/UpgradeManager.java
index 9725f26ad3..3e0629e57c 100644
---
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/UpgradeManager.java
+++
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/UpgradeManager.java
@@ -19,26 +19,23 @@ package org.apache.hadoop.hdds.scm.cli.container.upgrade;
import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
-import org.apache.hadoop.hdds.protocol.DatanodeDetails;
-import org.apache.hadoop.ozone.container.common.utils.HddsVolumeUtil;
import org.apache.hadoop.ozone.container.common.volume.HddsVolume;
-import org.apache.hadoop.ozone.container.common.volume.MutableVolumeSet;
import org.apache.hadoop.ozone.container.common.volume.StorageVolume;
+
import org.apache.hadoop.ozone.container.metadata.DatanodeStoreSchemaThreeImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
-import static
org.apache.hadoop.hdds.scm.cli.container.upgrade.UpgradeUtils.getContainerDBPath;
/**
* This class manages v2 to v3 container upgrade.
@@ -49,74 +46,41 @@ public class UpgradeManager {
LoggerFactory.getLogger(UpgradeManager.class);
private final Map<String, DatanodeStoreSchemaThreeImpl>
- volumeStoreMap = new HashMap<>();
-
- public void run(OzoneConfiguration configuration) throws IOException {
- final DatanodeDetails detail =
- UpgradeUtils.getDatanodeDetails(configuration);
+ volumeStoreMap = new ConcurrentHashMap<>();
- final MutableVolumeSet dataVolumeSet = UpgradeUtils
- .getHddsVolumes(configuration, StorageVolume.VolumeType.DATA_VOLUME,
- detail.getUuidString());
-
- HddsVolumeUtil.loadAllHddsVolumeDbStore(dataVolumeSet, null, false, LOG);
- initVolumeStoreMap(dataVolumeSet, configuration);
- upgradeAll(dataVolumeSet, configuration);
- }
-
- public void initVolumeStoreMap(MutableVolumeSet dataVolumeSet,
- OzoneConfiguration configuration) throws IOException {
- for (StorageVolume storageVolume : dataVolumeSet.getVolumesList()) {
- final HddsVolume volume = (HddsVolume) storageVolume;
- final File containerDBPath = getContainerDBPath(volume);
- final DatanodeStoreSchemaThreeImpl datanodeStoreSchemaThree =
- new DatanodeStoreSchemaThreeImpl(configuration,
- containerDBPath.getAbsolutePath(), false);
- volumeStoreMap.put(volume.getStorageDir().getAbsolutePath(),
- datanodeStoreSchemaThree);
- }
- }
-
- public List<Result> upgradeAll(MutableVolumeSet volumeSet,
- OzoneConfiguration configuration) {
+ public List<Result> run(OzoneConfiguration configuration,
+ List<HddsVolume> volumes) throws IOException {
List<Result> results = new ArrayList<>();
- final List<StorageVolume> volumesList = volumeSet.getVolumesList();
- Map<HddsVolume, CompletableFuture<Result>> volumeFutures =
- new HashMap<>();
+ Map<HddsVolume, CompletableFuture<Result>> volumeFutures = new HashMap<>();
long startTime = System.currentTimeMillis();
- LOG.info("Start upgrade {} volumes container LayoutVersion",
- volumesList.size());
-
- for (StorageVolume volume : volumesList) {
+ LOG.info("Start to upgrade {} volume(s)", volumes.size());
+ for (StorageVolume volume : volumes) {
final HddsVolume hddsVolume = (HddsVolume) volume;
final UpgradeTask task =
- new UpgradeTask(configuration, hddsVolume,
- getDBStore(hddsVolume));
-
- final CompletableFuture<Result> future =
- task.getUpgradeFutureByVolume();
+ new UpgradeTask(configuration, hddsVolume, volumeStoreMap);
+ final CompletableFuture<Result> future = task.getUpgradeFuture();
volumeFutures.put(hddsVolume, future);
}
- for (Map.Entry<HddsVolume, CompletableFuture<Result>> entry : volumeFutures
- .entrySet()) {
+ for (Map.Entry<HddsVolume, CompletableFuture<Result>> entry :
+ volumeFutures.entrySet()) {
final HddsVolume hddsVolume = entry.getKey();
final CompletableFuture<Result> volumeFuture = entry.getValue();
try {
final Result result = volumeFuture.get();
results.add(result);
- LOG.info("Finish upgrade containers on volume {}, result {}",
- hddsVolume.getVolumeRootDir(), result);
+ LOG.info("Finish upgrading containers on volume {}, {}",
+ hddsVolume.getVolumeRootDir(), result.toString());
} catch (Exception e) {
- LOG.error("Upgrade containers on volume {} failed",
+ LOG.error("Failed to upgrade containers on volume {}",
hddsVolume.getVolumeRootDir(), e);
}
}
- LOG.info("Upgrade all volume container LayoutVersion costs {}s",
- (System.currentTimeMillis() - startTime) / 1000);
+ LOG.info("It took {}ms to finish all volume upgrade.",
+ (System.currentTimeMillis() - startTime));
return results;
}
@@ -159,6 +123,10 @@ public class UpgradeManager {
return resultMap;
}
+ public boolean isSuccess() {
+ return this.status == Status.SUCCESS;
+ }
+
public void success() {
this.endTimeMs = System.currentTimeMillis();
this.status = Status.SUCCESS;
@@ -173,21 +141,23 @@ public class UpgradeManager {
@Override
public String toString() {
final StringBuilder stringBuilder = new StringBuilder();
- stringBuilder.append("Result{");
- stringBuilder.append("volumeDir=");
+ stringBuilder.append("Result:{");
+ stringBuilder.append("hddsRootDir=");
stringBuilder.append(getHddsVolume().getHddsRootDir());
stringBuilder.append(", resultList=");
AtomicLong total = new AtomicLong(0L);
- resultMap.forEach((k, r) -> {
- stringBuilder.append(r.toString());
- stringBuilder.append("\n");
- total.addAndGet(r.getTotalRow());
- });
+ if (resultMap != null) {
+ resultMap.forEach((k, r) -> {
+ stringBuilder.append(r.toString());
+ stringBuilder.append("\n");
+ total.addAndGet(r.getTotalRow());
+ });
+ }
stringBuilder.append(", totalRow=");
stringBuilder.append(total.get());
stringBuilder.append(", costMs=");
stringBuilder.append(getCost());
- stringBuilder.append("ms, status=");
+ stringBuilder.append(", status=");
stringBuilder.append(status);
if (e != null) {
stringBuilder.append(", Exception=");
diff --git
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/UpgradeTask.java
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/UpgradeTask.java
index cb21cd978a..5d12b12bc7 100644
---
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/UpgradeTask.java
+++
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/UpgradeTask.java
@@ -18,6 +18,7 @@
package org.apache.hadoop.hdds.scm.cli.container.upgrade;
import com.google.common.base.Preconditions;
+import org.apache.commons.io.FileUtils;
import org.apache.hadoop.hdds.StringUtils;
import org.apache.hadoop.hdds.conf.ConfigurationSource;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
@@ -32,6 +33,8 @@ import org.apache.hadoop.ozone.common.Storage;
import org.apache.hadoop.ozone.container.common.helpers.ContainerUtils;
import org.apache.hadoop.ozone.container.common.impl.ContainerData;
import org.apache.hadoop.ozone.container.common.impl.ContainerDataYaml;
+import org.apache.hadoop.ozone.container.common.utils.DatanodeStoreCache;
+import org.apache.hadoop.ozone.container.common.utils.RawDB;
import org.apache.hadoop.ozone.container.common.volume.HddsVolume;
import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainer;
import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainerData;
@@ -46,11 +49,16 @@ import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Date;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
+import static org.apache.hadoop.ozone.OzoneConsts.CONTAINER_DB_NAME;
+
/**
* This class implements the v2 to v3 container upgrade process.
*/
@@ -61,22 +69,27 @@ public class UpgradeTask {
private final ConfigurationSource config;
private final HddsVolume hddsVolume;
- private final DatanodeStoreSchemaThreeImpl datanodeStoreSchemaThree;
+ private DatanodeStoreSchemaThreeImpl dataStore;
+ private final Map volumeStoreMap;
private static final String BACKUP_CONTAINER_DATA_FILE_SUFFIX = ".backup";
+ public static final String UPGRADE_COMPLETE_FILE_NAME = "upgrade.complete";
+ public static final String UPGRADE_LOCK_FILE_NAME = "upgrade.lock";
+
private static final Set<String> COLUMN_FAMILIES_NAME =
(new DatanodeSchemaTwoDBDefinition("", new OzoneConfiguration()))
.getMap().keySet();
- public UpgradeTask(ConfigurationSource config,
- HddsVolume hddsVolume,
- DatanodeStoreSchemaThreeImpl datanodeStoreSchemaThree) {
+ public UpgradeTask(ConfigurationSource config, HddsVolume hddsVolume,
+ Map storeMap) {
this.config = config;
this.hddsVolume = hddsVolume;
- this.datanodeStoreSchemaThree = datanodeStoreSchemaThree;
+ this.volumeStoreMap = storeMap;
}
- public CompletableFuture<UpgradeManager.Result> getUpgradeFutureByVolume() {
+ public CompletableFuture<UpgradeManager.Result> getUpgradeFuture() {
+ final File lockFile = UpgradeUtils.getVolumeUpgradeLockFile(hddsVolume);
+
return CompletableFuture.supplyAsync(() -> {
final UpgradeManager.Result result =
@@ -88,63 +101,111 @@ public class UpgradeTask {
Preconditions.checkNotNull(hddsVolumeRootDir, "hddsVolumeRootDir" +
"cannot be null");
- //filtering storage directory
- File[] storageDirs = hddsVolumeRootDir.listFiles(File::isDirectory);
-
- if (storageDirs == null) {
+ // check CID directory and current file
+ File clusterIDDir = new File(hddsVolume.getStorageDir(),
+ hddsVolume.getClusterID());
+ if (!clusterIDDir.exists() || !clusterIDDir.isDirectory()) {
+ result.fail(new Exception("Volume " + hddsVolumeRootDir +
+ " is in an inconsistent state. Expected " +
+ "clusterID directory " + clusterIDDir +
+ " is not found or not a directory."));
+ return result;
+ }
+ File currentDir = new File(clusterIDDir, Storage.STORAGE_DIR_CURRENT);
+ if (!currentDir.exists() || !currentDir.isDirectory()) {
result.fail(new Exception(
- "Storage dir not found for the volume " + hddsVolumeRootDir +
- ", skipped upgrade."));
+ "Current dir " + currentDir + " is not found or not a directory,"
+ + " skip upgrade."));
return result;
}
- if (storageDirs.length > 0) {
- File clusterIDDir = new File(hddsVolume.getStorageDir(),
- hddsVolume.getClusterID());
- File idDir = clusterIDDir;
- if (storageDirs.length == 1 && !clusterIDDir.exists()) {
- idDir = storageDirs[0];
- } else {
- if (!clusterIDDir.exists()) {
- result.fail(new Exception("Volume " + hddsVolumeRootDir +
- " is in an inconsistent state. Expected " +
- "clusterID directory " + clusterIDDir + " not found."));
- return result;
- }
- }
-
- LOG.info("Start to upgrade containers on volume {}",
hddsVolumeRootDir);
- File currentDir = new File(idDir, Storage.STORAGE_DIR_CURRENT);
-
- if (!currentDir.exists()) {
- result.fail(new Exception(
- "Storage current dir not found for the volume " +
- currentDir + ", skipped upgrade."));
+ try {
+ // create lock file
+ if (!lockFile.createNewFile()) {
+ result.fail(new Exception("Upgrade lock file already exists " +
+ lockFile.getAbsolutePath() + ", skip upgrade."));
return result;
}
- File[] containerTopDirs = currentDir.listFiles();
- if (containerTopDirs != null) {
- for (File containerTopDir : containerTopDirs) {
- try {
- final List<UpgradeContainerResult> results =
- upgradeSubContainerDir(containerTopDir);
- resultList.addAll(results);
- } catch (IOException e) {
- result.fail(e);
- return result;
- }
- }
+ } catch (IOException e) {
+ result.fail(new Exception("Failed to create upgrade lock file " +
+ lockFile.getAbsolutePath() + ", skip upgrade."));
+ return result;
+ }
+
+ // check complete file again
+ final File completeFile =
+ UpgradeUtils.getVolumeUpgradeCompleteFile(hddsVolume);
+ if (completeFile.exists()) {
+ result.fail(new Exception("Upgrade complete file already exists " +
+ completeFile.getAbsolutePath() + ", skip upgrade."));
+ if (!lockFile.delete()) {
+ LOG.warn("Failed to delete upgrade lock file {}.", lockFile);
}
- } else {
+ return result;
+ }
+
+ // backup DB directory
+ final File volumeDBPath;
+ try {
+ volumeDBPath = getVolumeDBPath(hddsVolume);
+ dbBackup(volumeDBPath);
+ } catch (IOException e) {
+ result.fail(new Exception(e.getMessage() + ", skip upgrade."));
+ return result;
+ }
+
+ // load DB store
+ try {
+ hddsVolume.loadDbStore(false);
+ RawDB db = DatanodeStoreCache.getInstance().getDB(
+ volumeDBPath.getAbsolutePath(), config);
+ dataStore = (DatanodeStoreSchemaThreeImpl) db.getStore();
+ volumeStoreMap.put(
+ hddsVolume.getStorageDir().getAbsolutePath(), dataStore);
+ } catch (IOException e) {
result.fail(new Exception(
- "Storage dir not found for the volume " + hddsVolumeRootDir +
- ", skipped upgrade."));
+ "Failed to load db for volume " + hddsVolume.getVolumeRootDir() +
+ " for " + e.getMessage() + ", skip upgrade."));
return result;
}
+ LOG.info("Start to upgrade containers on volume {}",
+ hddsVolume.getVolumeRootDir());
+ File[] containerTopDirs = currentDir.listFiles();
+ if (containerTopDirs != null) {
+ for (File containerTopDir : containerTopDirs) {
+ try {
+ final List<UpgradeContainerResult> results =
+ upgradeSubContainerDir(containerTopDir);
+ resultList.addAll(results);
+ } catch (IOException e) {
+ result.fail(e);
+ return result;
+ }
+ }
+ }
+
result.setResultList(resultList);
result.success();
return result;
+ }).whenComplete((r, e) -> {
+ final File hddsRootDir = r.getHddsVolume().getHddsRootDir();
+ final File file =
+ UpgradeUtils.getVolumeUpgradeCompleteFile(r.getHddsVolume());
+ // create a flag file
+ if (e == null && r.isSuccess()) {
+ try {
+ UpgradeUtils.createFile(file);
+ } catch (IOException ioe) {
+ LOG.warn("Failed to create upgrade complete file {}.", file, ioe);
+ }
+ }
+ if (lockFile.exists()) {
+ boolean deleted = lockFile.delete();
+ if (!deleted) {
+ LOG.warn("Failed to delete upgrade lock file {}.", file);
+ }
+ }
});
}
@@ -172,58 +233,46 @@ public class UpgradeTask {
private ContainerData parseContainerData(File containerDir) {
try {
- File containerFile = ContainerUtils.getContainerFile(
- containerDir);
- long containerID =
- ContainerUtils.getContainerID(containerDir);
- if (containerFile.exists()) {
- try {
- ContainerData containerData =
- ContainerDataYaml.readContainerFile(
- containerFile);
- if (containerID != containerData.getContainerID()) {
- LOG.error("Invalid ContainerID in file {}. " +
- "Skipping loading of this container.",
- containerFile);
- return null;
- }
- if (containerData.getContainerType().equals(
- ContainerProtos.ContainerType.KeyValueContainer) &&
- containerData instanceof KeyValueContainerData) {
- KeyValueContainerData kvContainerData =
- (KeyValueContainerData)
- containerData;
- containerData.setVolume(hddsVolume);
- KeyValueContainerUtil
- .parseKVContainerData(kvContainerData, config);
-
- return kvContainerData;
- } else {
- LOG.error("Only KeyValueContainer support. ");
- return null;
- }
-
- } catch (IOException ex) {
- LOG.error(
- "Failed to parse ContainerFile for ContainerID: {}",
- containerID, ex);
+ File containerFile = ContainerUtils.getContainerFile(containerDir);
+ long containerID = ContainerUtils.getContainerID(containerDir);
+ if (!containerFile.exists()) {
+ LOG.error("Missing .container file: {}.", containerDir);
+ return null;
+ }
+ try {
+ ContainerData containerData =
+ ContainerDataYaml.readContainerFile(containerFile);
+ if (containerID != containerData.getContainerID()) {
+ LOG.error("ContainerID in file {} mismatch with expected {}.",
+ containerFile, containerID);
+ return null;
+ }
+ if (containerData.getContainerType().equals(
+ ContainerProtos.ContainerType.KeyValueContainer) &&
+ containerData instanceof KeyValueContainerData) {
+ KeyValueContainerData kvContainerData =
+ (KeyValueContainerData) containerData;
+ containerData.setVolume(hddsVolume);
+ KeyValueContainerUtil.parseKVContainerData(kvContainerData, config);
+ return kvContainerData;
+ } else {
+ LOG.error("Container is not KeyValueContainer type: {}.",
+ containerDir);
return null;
}
- } else {
- LOG.error("Missing .container file for ContainerID: {}",
- containerDir.getName());
+ } catch (IOException ex) {
+ LOG.error("Failed to parse ContainerFile: {}.", containerFile, ex);
return null;
}
} catch (Throwable e) {
- LOG.error("Failed to load container from {}",
- containerDir.getAbsolutePath(), e);
+ LOG.error("Failed to load container: {}.", containerDir, e);
return null;
}
}
private void upgradeContainer(ContainerData containerData,
UpgradeContainerResult result) throws IOException {
- final DBStore targetDBStore = datanodeStoreSchemaThree.getStore();
+ final DBStore targetDBStore = dataStore.getStore();
// open container schema v2 rocksdb
final DatanodeStore dbStore = BlockUtils
@@ -306,6 +355,30 @@ public class UpgradeTask {
}
}
+ public File getVolumeDBPath(HddsVolume volume) throws IOException {
+ File clusterIdDir = new File(volume.getStorageDir(),
volume.getClusterID());
+ File storageIdDir = new File(clusterIdDir, volume.getStorageID());
+ File containerDBPath = new File(storageIdDir, CONTAINER_DB_NAME);
+ if (containerDBPath.exists() && containerDBPath.isDirectory()) {
+ return containerDBPath;
+ } else {
+ throw new IOException("DB " + containerDBPath +
+ " doesn't exist or is not a directory");
+ }
+ }
+
+ public void dbBackup(File dbPath) throws IOException {
+ final File backup = new File(dbPath.getParentFile(),
+ new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss").format(new Date()) +
+ "-" + dbPath.getName() + ".backup");
+ if (backup.exists()) {
+ throw new IOException("Backup dir " + backup + "already exists");
+ } else {
+ FileUtils.copyDirectory(dbPath, backup, true);
+ System.out.println("DB " + dbPath + " is backup to " + backup);
+ }
+ }
+
/**
* This class represents upgrade v2 to v3 container result.
*/
@@ -368,7 +441,7 @@ public class UpgradeTask {
@Override
public String toString() {
final StringBuilder stringBuilder = new StringBuilder();
- stringBuilder.append("Result{");
+ stringBuilder.append("Result:{");
stringBuilder.append("containerID=");
stringBuilder.append(originContainerData.getContainerID());
stringBuilder.append(", originContainerSchemaVersion=");
diff --git
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/UpgradeUtils.java
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/UpgradeUtils.java
index b9fa820d71..9047bd5fc7 100644
---
a/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/UpgradeUtils.java
+++
b/hadoop-hdds/tools/src/main/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/UpgradeUtils.java
@@ -27,7 +27,12 @@ import
org.apache.hadoop.ozone.container.common.volume.MutableVolumeSet;
import org.apache.hadoop.ozone.container.common.volume.StorageVolume;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
import static org.apache.hadoop.ozone.OzoneConsts.CONTAINER_DB_NAME;
@@ -59,4 +64,24 @@ public final class UpgradeUtils {
public static File getContainerDBPath(HddsVolume volume) {
return new File(volume.getDbParentDir(), CONTAINER_DB_NAME);
}
+
+ public static File getVolumeUpgradeCompleteFile(HddsVolume volume) {
+ return new File(volume.getHddsRootDir(),
+ UpgradeTask.UPGRADE_COMPLETE_FILE_NAME);
+ }
+
+ public static File getVolumeUpgradeLockFile(HddsVolume volume) {
+ return new File(volume.getHddsRootDir(),
+ UpgradeTask.UPGRADE_LOCK_FILE_NAME);
+ }
+
+ public static boolean createFile(File file) throws IOException {
+ final Date date = new Date();
+ try (Writer writer = new OutputStreamWriter(new FileOutputStream(file),
+ StandardCharsets.UTF_8)) {
+ writer.write(date.toString());
+ }
+ return file.exists();
+ }
+
}
diff --git
a/hadoop-hdds/tools/src/test/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/TestUpgradeManager.java
b/hadoop-hdds/tools/src/test/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/TestUpgradeManager.java
index 9f4c0aa26f..ee02f0e506 100644
---
a/hadoop-hdds/tools/src/test/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/TestUpgradeManager.java
+++
b/hadoop-hdds/tools/src/test/java/org/apache/hadoop/hdds/scm/cli/container/upgrade/TestUpgradeManager.java
@@ -159,9 +159,9 @@ public class TestUpgradeManager {
shutdownAllVolume();
final UpgradeManager upgradeManager = new UpgradeManager();
- upgradeManager.initVolumeStoreMap(volumeSet, CONF);
final List<UpgradeManager.Result> results =
- upgradeManager.upgradeAll(volumeSet, CONF);
+ upgradeManager.run(CONF,
+ StorageVolumeUtil.getHddsVolumesList(volumeSet.getVolumesList()));
checkV3MetaData(keyValueContainerBlockDataMap, results, upgradeManager);
}
@@ -269,8 +269,7 @@ public class TestUpgradeManager {
private void checkV3MetaData(Map<KeyValueContainerData,
Map<String, BlockData>> blockDataMap, List<UpgradeManager.Result>
results,
- UpgradeManager upgradeManager)
- throws IOException {
+ UpgradeManager upgradeManager) throws IOException {
Map<Long, UpgradeTask.UpgradeContainerResult> resultMap = new HashMap<>();
for (UpgradeManager.Result result : results) {
diff --git
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneContainerUpgradeShell.java
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneContainerUpgradeShell.java
new file mode 100644
index 0000000000..5f2380e97e
--- /dev/null
+++
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/shell/TestOzoneContainerUpgradeShell.java
@@ -0,0 +1,249 @@
+/*
+ * 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.shell;
+
+import com.google.common.base.Preconditions;
+import org.apache.hadoop.hdds.client.ReplicationFactor;
+import org.apache.hadoop.hdds.client.ReplicationType;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.protocol.DatanodeDetails;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+import org.apache.hadoop.hdds.scm.cli.container.ContainerCommands;
+import org.apache.hadoop.hdds.scm.cli.container.UpgradeSubcommand;
+import org.apache.hadoop.hdds.scm.container.ContainerID;
+import org.apache.hadoop.hdds.scm.container.ContainerInfo;
+import org.apache.hadoop.hdds.scm.container.replication.ReplicationManager;
+import org.apache.hadoop.hdds.utils.HddsServerUtil;
+import org.apache.hadoop.hdds.utils.IOUtils;
+import org.apache.hadoop.hdds.utils.db.CodecTestUtil;
+import org.apache.hadoop.hdds.utils.db.managed.ManagedRocksObjectMetrics;
+import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
+import org.apache.hadoop.ozone.HddsDatanodeService;
+import org.apache.hadoop.ozone.MiniOzoneCluster;
+import org.apache.hadoop.ozone.OzoneTestUtils;
+import org.apache.hadoop.ozone.TestDataUtil;
+import org.apache.hadoop.ozone.client.OzoneClient;
+import org.apache.hadoop.ozone.client.OzoneClientFactory;
+import org.apache.hadoop.ozone.container.common.helpers.ContainerUtils;
+import org.apache.hadoop.ozone.container.common.utils.ContainerCache;
+import org.apache.hadoop.ozone.container.common.utils.DatanodeStoreCache;
+import org.apache.hadoop.ozone.om.helpers.OmKeyArgs;
+import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfo;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import picocli.CommandLine;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static
org.apache.hadoop.hdds.HddsConfigKeys.HDDS_COMMAND_STATUS_REPORT_INTERVAL;
+import static
org.apache.hadoop.hdds.HddsConfigKeys.HDDS_CONTAINER_REPORT_INTERVAL;
+import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_HEARTBEAT_INTERVAL;
+import static
org.apache.hadoop.hdds.HddsConfigKeys.HDDS_PIPELINE_REPORT_INTERVAL;
+import static
org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_SCM_HEARTBEAT_PROCESS_INTERVAL;
+import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ADMINISTRATORS;
+import static
org.apache.hadoop.ozone.container.common.statemachine.DatanodeConfiguration.CONTAINER_SCHEMA_V3_ENABLED;
+
+/**
+ * Test Ozone Container upgrade shell.
+ */
+public class TestOzoneContainerUpgradeShell {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(TestOzoneContainerUpgradeShell.class);
+ private static String omServiceId;
+ private static String clusterId;
+ private static String scmId;
+ private static MiniOzoneCluster cluster = null;
+ private static OzoneClient client;
+ private static OzoneConfiguration conf = null;
+ private static final String VOLUME_NAME = UUID.randomUUID().toString();
+ private static final String BUCKET_NAME = UUID.randomUUID().toString();
+
+ protected static void startCluster() throws Exception {
+ // Init HA cluster
+ omServiceId = "om-service-test-upgrade-container1";
+ clusterId = UUID.randomUUID().toString();
+ scmId = UUID.randomUUID().toString();
+ final int numDNs = 3;
+ cluster = MiniOzoneCluster.newBuilder(conf).setClusterId(clusterId)
+ .setScmId(scmId).setOMServiceId(omServiceId).setNumDatanodes(numDNs)
+ .build();
+ cluster.waitForClusterToBeReady();
+ client = cluster.newClient();
+ }
+
+ @BeforeAll
+ public static void init() throws Exception {
+ conf = new OzoneConfiguration();
+ conf.set(OZONE_ADMINISTRATORS, "*");
+ conf.setTimeDuration(OZONE_SCM_HEARTBEAT_PROCESS_INTERVAL, 100,
+ TimeUnit.MILLISECONDS);
+ conf.setTimeDuration(HDDS_HEARTBEAT_INTERVAL, 1, SECONDS);
+ conf.setTimeDuration(HDDS_PIPELINE_REPORT_INTERVAL, 1, SECONDS);
+ conf.setTimeDuration(HDDS_COMMAND_STATUS_REPORT_INTERVAL, 1, SECONDS);
+ conf.setTimeDuration(HDDS_CONTAINER_REPORT_INTERVAL, 1, SECONDS);
+ ReplicationManager.ReplicationManagerConfiguration replicationConf =
+ conf.getObject(
+ ReplicationManager.ReplicationManagerConfiguration.class);
+ replicationConf.setInterval(Duration.ofSeconds(1));
+ conf.setFromObject(replicationConf);
+ // gen schema v2 container
+ conf.setBoolean(CONTAINER_SCHEMA_V3_ENABLED, false);
+
+ startCluster();
+ }
+
+ public List<OzoneConfiguration> getDatanodeConfigs() {
+ List<OzoneConfiguration> configList = new ArrayList<>();
+ for (HddsDatanodeService datanodeService : cluster.getHddsDatanodes()) {
+ OzoneConfiguration datanodeConf = datanodeService.getConf();
+ configList.add(datanodeConf);
+ }
+ return configList;
+ }
+
+ @Test
+ public void testNormalContainerUpgrade() throws Exception {
+ writeKeyAndCloseContainer();
+ List<OzoneConfiguration> datanodeConfigs = getDatanodeConfigs();
+ HddsDatanodeService hddsDatanodeService =
cluster.getHddsDatanodes().get(0);
+ DatanodeDetails dni = hddsDatanodeService.getDatanodeDetails();
+ OzoneConfiguration datanodeConf = datanodeConfigs.get(0);
+
+ // create volume rocksdb
+ OzoneConfiguration newConf = new OzoneConfiguration(datanodeConf);
+ newConf.setBoolean(CONTAINER_SCHEMA_V3_ENABLED, true);
+ hddsDatanodeService.setConfiguration(newConf);
+ cluster.restartHddsDatanode(dni, true);
+
+ nodeOperationalStateToMaintenance(dni, datanodeConf);
+
+ shutdownCluster();
+
+ // datanode1 test check all pass & upgrade success
+ UpgradeSubcommand.setOzoneConfiguration(datanodeConf);
+ StringWriter stdout = new StringWriter();
+ PrintWriter pstdout = new PrintWriter(stdout);
+ CommandLine commandLine = upgradeCommand(pstdout);
+
+ String[] args = new String[]{"upgrade", "--yes"};
+ int exitCode = commandLine.execute(args);
+ Assertions.assertEquals(0, exitCode);
+
+ // datanode2 NodeOperationalState is IN_SERVICE upgrade fail.
+ OzoneConfiguration datanode2Conf = datanodeConfigs.get(1);
+ UpgradeSubcommand.setOzoneConfiguration(datanode2Conf);
+ StringWriter stdout2 = new StringWriter();
+ PrintWriter pstdout2 = new PrintWriter(stdout2);
+ CommandLine commandLine2 = upgradeCommand(pstdout2);
+
+ String[] args2 = new String[]{"upgrade", "--yes"};
+ int exit2Code = commandLine2.execute(args2);
+
+ Assertions.assertEquals(0, exit2Code);
+ String cmdOut = stdout2.toString();
+ Assertions.assertTrue(cmdOut.contains("IN_MAINTENANCE"));
+ }
+
+ private CommandLine upgradeCommand(PrintWriter pstdout) {
+ return new CommandLine(new ContainerCommands()).setOut(pstdout);
+ }
+
+ private static ContainerInfo writeKeyAndCloseContainer() throws Exception {
+ final String keyName = UUID.randomUUID().toString();
+ writeKey(keyName);
+ return closeContainerForKey(keyName);
+ }
+
+ private static void writeKey(String keyName) throws IOException {
+ try (OzoneClient client = OzoneClientFactory.getRpcClient(conf)) {
+ TestDataUtil.createVolumeAndBucket(client, VOLUME_NAME, BUCKET_NAME);
+ TestDataUtil.createKey(
+
client.getObjectStore().getVolume(VOLUME_NAME).getBucket(BUCKET_NAME),
+ keyName, ReplicationFactor.THREE, ReplicationType.RATIS, "test");
+ }
+ }
+
+ private static ContainerInfo closeContainerForKey(String keyName)
+ throws IOException, TimeoutException, InterruptedException {
+ OmKeyArgs keyArgs = new OmKeyArgs.Builder().setVolumeName(VOLUME_NAME)
+ .setBucketName(BUCKET_NAME).setKeyName(keyName).build();
+
+ OmKeyLocationInfo omKeyLocationInfo =
+ cluster.getOzoneManager().lookupKey(keyArgs).getKeyLocationVersions()
+ .get(0).getBlocksLatestVersionOnly().get(0);
+
+ ContainerInfo container =
+
cluster.getStorageContainerManager().getContainerManager().getContainer(
+ ContainerID.valueOf(omKeyLocationInfo.getContainerID()));
+
+ OzoneTestUtils.closeContainer(cluster.getStorageContainerManager(),
+ container);
+ return container;
+ }
+
+ public static void shutdownCluster() throws InterruptedException {
+
+ try {
+ IOUtils.closeQuietly(client);
+ if (cluster != null) {
+ List<OzoneConfiguration> dnConfigs =
cluster.getHddsDatanodes().stream()
+ .map(HddsDatanodeService::getConf).collect(Collectors.toList());
+
+ DatanodeStoreCache.setMiniClusterMode(false);
+
+ cluster.stop();
+ ContainerCache.getInstance(conf).shutdownCache();
+
+
+ for (OzoneConfiguration dnConfig : dnConfigs) {
+ ContainerCache.getInstance(dnConfig).shutdownCache();
+ }
+ DefaultMetricsSystem.shutdown();
+ ManagedRocksObjectMetrics.INSTANCE.assertNoLeaks();
+ CodecTestUtil.gc();
+ }
+ } catch (Exception e) {
+ LOG.error("Exception while shutting down the cluster.", e);
+ }
+ }
+
+ private void nodeOperationalStateToMaintenance(DatanodeDetails dnDetails,
+ OzoneConfiguration config) throws IOException {
+ dnDetails.setPersistedOpState(
+ HddsProtos.NodeOperationalState.IN_MAINTENANCE);
+ String idFilePath = HddsServerUtil.getDatanodeIdFilePath(config);
+ Preconditions.checkNotNull(idFilePath);
+ File idFile = new File(idFilePath);
+ ContainerUtils.writeDatanodeDetailsTo(dnDetails, idFile, config);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]