Skip to content

HDDS-15715. Add helpful CLI flags to finalization CLIs#10678

Open
dombizita wants to merge 8 commits into
apache:HDDS-14496-zdufrom
dombizita:HDDS-15715
Open

HDDS-15715. Add helpful CLI flags to finalization CLIs#10678
dombizita wants to merge 8 commits into
apache:HDDS-14496-zdufrom
dombizita:HDDS-15715

Conversation

@dombizita

@dombizita dombizita commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

Added new CLI flags to the upgrade finalization CLI:

  • finalize --wait: the client will periodically poll the cluster for status from OM until the whole cluster is finalized. The finalize command is idempotent so waiting can be resumed at any time
  • status --json: json version of the status output for scripting
  • status --verbose: includes internal information like OM and SCM apparent versions, the min and max DN apparent versions in the cluster

Used Claude Opus 4.8 for planning and coding, reviewed by me.

What is the link to the Apache JIRA

https://issues.apache.org/jira/browse/HDDS-15715

How was this patch tested?

Added unit tests, green run on my fork: https://github.com/dombizita/ozone/actions/runs/28660447709

@github-actions github-actions Bot added the zdu Pull requests for Zero Downtime Upgrade (ZDU) https://issues.apache.org/jira/browse/HDDS-14496 label Jul 6, 2026
@errose28
errose28 self-requested a review July 7, 2026 18:42

@errose28 errose28 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding this @dombizita.

Comment thread hadoop-hdds/interface-client/src/main/proto/hdds.proto Outdated
@errose28

Copy link
Copy Markdown
Contributor

Thanks for the updates. Can you check on the CI failures? This should re-run against the base branch as well since we just merged from master.

@errose28 errose28 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates. Left some more comments.

Also here is an AI generated test we can add to cover the case of RPC failure during the wait loop. This assumes the desired behavior in this case is to exit the loop though, which I'm not sure is the case. It might be better to adjust the wait loop to print to stderr when this happens and retry automatically on the next interval, and update this test accordingly.

diff --git a/hadoop-ozone/cli-admin/src/test/java/org/apache/hadoop/ozone/admin/upgrade/TestFinalizeSubCommand.java b/hadoop-ozone/cli-admin/src/test/java/org/apache/hadoop/ozone/admin/upgrade/TestFinalizeSubCommand.java
index e6e3a5ed48..70bf533b11 100644
--- a/hadoop-ozone/cli-admin/src/test/java/org/apache/hadoop/ozone/admin/upgrade/TestFinalizeSubCommand.java
+++ b/hadoop-ozone/cli-admin/src/test/java/org/apache/hadoop/ozone/admin/upgrade/TestFinalizeSubCommand.java
@@ -169,6 +169,18 @@ public void testWaitFlagPollsUntilFinalized() throws Exception {
     verify(omClient, times(3)).queryUpgradeStatus();
   }
 
+  @Test
+  public void testWaitFlagRpcFailurePrintsMessageAndReturnsNonZero() throws Exception {
+    when(omClient.queryUpgradeStatus()).thenThrow(new IOException("RPC timeout"));
+
+    new CommandLine(cmd).parseArgs("--wait");
+    assertEquals(1, cmd.call());
+
+    String errOutput = errContent.toString(DEFAULT_ENCODING);
+    assertTrue(errOutput.contains("Failed to query upgrade status"));
+    assertTrue(errOutput.contains("RPC timeout"));
+  }
+
   @Test
   public void testWaitFlagInterruptIsHandledCleanly() throws Exception {
     // Make the poll interval long enough that the interrupt lands during the sleep (after the first poll).

try {
result.set(cmd.call());
} catch (Exception ignored) {
// The command handles interruption internally and should not throw.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If no exception is expected we should fail the test if one is encountered.

Comment on lines 67 to +69
out().println("Cluster finalization has been started. Monitor progress with `ozone admin upgrade status`");

if (wait) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably alter this message if --wait is provided to indicate that we are waiting for finalization to complete.

*/
@CommandLine.Command(
name = "finalize",
description = "Initiates the the process to finalize a cluster upgrade.",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Existing issue, but we can fix it here.

Suggested change
description = "Initiates the process to finalize a cluster upgrade. This command is idempotent.",

Comment on lines +102 to +104
out().printf("Waiting for finalization: OM=%s, SCM=%s, datanodes=%d/%d%n",
status.getOmFinalized(), hdds.getScmFinalized(),
hdds.getNumDatanodesFinalized(), hdds.getNumDatanodesTotal());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we use the regular status output here instead of making a new one?

Comment on lines +119 to +124
static boolean isClusterFinalized(QueryUpgradeStatusResponse status) {
HddsProtos.UpgradeStatus hdds = status.getHddsStatus();
return status.getOmFinalized()
&& hdds.getScmFinalized()
&& hdds.getNumDatanodesFinalized() == hdds.getNumDatanodesTotal();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this again, I think we should add a new field to the proto to represent this, with this computation happening on the server side, i.e. OM returns clusterFinalized = hdds.isFinalized() && omFinalized and the client just consumes clusterFinalized to make its decision. It can still print the counts, but this allows us to change the definition of finalized on the server side without impacting old clients.

This is similar to what we did with the shouldFinalize field that OM gets from SCM instead of checking the SCM and datanode counts directly.

}

@Test
public void testJsonFlagWithVerboseIncludesVersions() throws Exception {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The names of this and the previous test make it seem like the verbose flag affects json output, which is doesn't. If this is intentional, then there should be one test for all json output and it should also assert that content is identical when verbose is passed.

Comment on lines +1218 to +1219
throw new SCMException("Cannot query upgrade status while SCM is in safe mode. Wait until SCM exits "
+ "safe mode and try again.", ResultCodes.SAFE_MODE_EXCEPTION);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should update OM in the PR as well to handle the SCM exception with this result code and return a propagate a coherent OMException back to the user, probably with result code UNSUPPORTED_OPERATION like #10777 does when the SCM versions don't match.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

zdu Pull requests for Zero Downtime Upgrade (ZDU) https://issues.apache.org/jira/browse/HDDS-14496

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants