Migrate command `autorecovery`
Descriptions of the changes in this PR:
- Using `bkctl` run command `autorecovery`
### Motivation
#2009
Reviewers: Jia Zhai <zhaijia@apache.org>, Sijie Guo <sijie@apache.org>
This closes #2010 from zymap/command-autorecovery and squashes the following commits:
6fcd96904 [Yong Zhang] Fix validation
cd383f372 [Yong Zhang] Rename package
efb573221 [Yong Zhang] Rename command
89da2852e [Yong Zhang] Fix error in bookieshell
a037501ee [Yong Zhang] Rename args
4bb36b0b3 [Yong Zhang] Fix imports postion
e41a742d3 [Yong Zhang] Add unit test for command `autorecovery`
b0c91f704 [Yong Zhang] Rename file
cb06f66de [Yong Zhang] Migrate command `autorecovery`
ed008f278 [Yong Zhang] Migrate command `whoisauditor`
5b8e0971a [Yong Zhang] Migrate command `Whatisinstanceid`
90c79444d [Yong Zhang] Migrate command `rebuild-db-ledger-locations-index`
848f8527f [Nicolas Michael] ISSUE #2053: Bugfix for Percentile Calculation in FastCodahale Timer Implementation
06f2b6f50 [Yong Zhang] Migrate command `updateledgers`
7ad5849b1 [Yong Zhang] Migrate command `regenerate-interleaved-storage-index-file`
d4dbb6bfb [Dongfa,Huang] Avoid useless verify if LedgerEntryRequest completed
5c150f283 [Enrico Olivelli] Release notes for 4.9.1
1246826ba [Yong Zhang] Migrate command `recover`
1d4cc71fd [Yong Zhang] Migrate command `localconsistencycheck`
67f83620e [Yong Zhang] Migrate command `readledger`
bfbd6b023 [Yong Zhang] Migrate command `decommission`
d40b8b69f [Yong Zhang] Migrate command `readlog`
95d145a15 [Yong Zhang] Migrate command `nukeexistingcluster`
e2b1dc7f3 [Yong Zhang] Migrate command `listunderreplicated`
0988e12c7 [bd2019us] ISSUE #2023: change cached thread pool to fixed thread pool
6a6d7bbd9 [Yong Zhang] Migrate command `initnewcluster`
c391fe58d [Yong Zhang] Migrate command `readlogmetadata`
120d67737 [Yong Zhang] Migrate command `lostbookierecoverydelay`
bf66235e5 [Yong Zhang] Migrate command `deleteledger`
751e55fa4 [Arvin] ISSUE #2020: close db properly to avoid open RocksDB failure at the second time
138a7ae85 [Yong Zhang] Migrate command `metadataformat`
b043d1694 [Yong Zhang] Migrate command `listledgers`
4573285db [Ivan Kelly] Docker autobuild hook
e3d807a32 [Like] Fix IDE complain as there are multi choices for error code
9524a9f4a [Yong Zhang] Migrate command `readjournal`
6c3f33f55 [Yong Zhang] Fix when met unexpect entry id crashed
e35a108c7 [Like] Fix error message for unrecognized number-of-bookies
5902ee27b [Boyang Jerry Peng] fix potential NPE when releasing entry that is null
6aa73ce05 [Ivan Kelly] [RELEASE] Update website to include documentation for 4.8.2
1448d12aa [Yong Zhang] Migrate command `listfilesondisk`
4de598379 [Yong Zhang] Issue #1987: Migrate command `convert-to-interleaved-storage`
468743e7e [Matteo Merli] In DbLedgerStorage use default values when config key is present but empty
f26a4cae0 [Ivan Kelly] Release notes for v4.8.2
ec2636cd2 [Yong Zhang] Issue #1985: Migrate command `convert-to-db-storage`
8cc7239ac [Yong Zhang] Issue #1982: Migrate command `bookiesanity`
fa90f0185 [Yong Zhang] Issue #1980: Migrate command `ledger` from shell to bkctl
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieShell.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieShell.java
index 3f307f5..eff70ed 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieShell.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/BookieShell.java
@@ -55,11 +55,10 @@
import org.apache.bookkeeper.conf.ServerConfiguration;
import org.apache.bookkeeper.meta.LedgerManager;
import org.apache.bookkeeper.meta.LedgerMetadataSerDe;
-import org.apache.bookkeeper.meta.LedgerUnderreplicationManager;
import org.apache.bookkeeper.net.BookieSocketAddress;
-import org.apache.bookkeeper.replication.ReplicationException;
import org.apache.bookkeeper.tools.cli.commands.autorecovery.ListUnderReplicatedCommand;
import org.apache.bookkeeper.tools.cli.commands.autorecovery.LostBookieRecoveryDelayCommand;
+import org.apache.bookkeeper.tools.cli.commands.autorecovery.ToggleCommand;
import org.apache.bookkeeper.tools.cli.commands.autorecovery.WhoIsAuditorCommand;
import org.apache.bookkeeper.tools.cli.commands.bookie.ConvertToDBStorageCommand;
import org.apache.bookkeeper.tools.cli.commands.bookie.ConvertToInterleavedStorageCommand;
@@ -114,7 +113,6 @@
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
-import org.apache.zookeeper.KeeperException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -1290,43 +1288,10 @@
boolean disable = cmdLine.hasOption("d");
boolean enable = cmdLine.hasOption("e");
- if (enable && disable) {
- LOG.error("Only one of -enable and -disable can be specified");
- printUsage();
- return 1;
- }
-
- runFunctionWithLedgerManagerFactory(bkConf, mFactory -> {
- try {
- try (LedgerUnderreplicationManager underreplicationManager =
- mFactory.newLedgerUnderreplicationManager()) {
- if (!enable && !disable) {
- boolean enabled = underreplicationManager.isLedgerReplicationEnabled();
- System.out.println("Autorecovery is " + (enabled ? "enabled." : "disabled."));
- } else if (enable) {
- if (underreplicationManager.isLedgerReplicationEnabled()) {
- LOG.warn("Autorecovery already enabled. Doing nothing");
- } else {
- LOG.info("Enabling autorecovery");
- underreplicationManager.enableLedgerReplication();
- }
- } else {
- if (!underreplicationManager.isLedgerReplicationEnabled()) {
- LOG.warn("Autorecovery already disabled. Doing nothing");
- } else {
- LOG.info("Disabling autorecovery");
- underreplicationManager.disableLedgerReplication();
- }
- }
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new UncheckedExecutionException(e);
- } catch (KeeperException | ReplicationException e) {
- throw new UncheckedExecutionException(e);
- }
- return null;
- });
+ ToggleCommand.AutoRecoveryFlags flags = new ToggleCommand.AutoRecoveryFlags()
+ .enable(enable).status(!disable && !enable);
+ ToggleCommand cmd = new ToggleCommand();
+ cmd.apply(bkConf, flags);
return 0;
}
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/ToggleCommand.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/ToggleCommand.java
new file mode 100644
index 0000000..c145715
--- /dev/null
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/ToggleCommand.java
@@ -0,0 +1,121 @@
+/*
+ * 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.bookkeeper.tools.cli.commands.autorecovery;
+
+import com.beust.jcommander.Parameter;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+import java.util.concurrent.ExecutionException;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import org.apache.bookkeeper.conf.ServerConfiguration;
+import org.apache.bookkeeper.meta.LedgerUnderreplicationManager;
+import org.apache.bookkeeper.meta.MetadataDrivers;
+import org.apache.bookkeeper.meta.exceptions.MetadataException;
+import org.apache.bookkeeper.replication.ReplicationException;
+import org.apache.bookkeeper.tools.cli.helpers.BookieCommand;
+import org.apache.bookkeeper.tools.framework.CliFlags;
+import org.apache.bookkeeper.tools.framework.CliSpec;
+import org.apache.zookeeper.KeeperException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Command to enable or disable auto recovery in the cluster.
+ */
+public class ToggleCommand extends BookieCommand<ToggleCommand.AutoRecoveryFlags> {
+
+ static final Logger LOG = LoggerFactory.getLogger(ToggleCommand.class);
+
+ private static final String NAME = "toggle";
+ private static final String DESC = "Enable or disable auto recovery in the cluster. Default is disable.";
+
+ public ToggleCommand() {
+ this(new AutoRecoveryFlags());
+ }
+
+ private ToggleCommand(AutoRecoveryFlags flags) {
+ super(CliSpec.<ToggleCommand.AutoRecoveryFlags>newBuilder()
+ .withName(NAME).withDescription(DESC)
+ .withFlags(flags).build());
+ }
+
+ /**
+ * Flags for auto recovery command.
+ */
+ @Accessors(fluent = true)
+ @Setter
+ public static class AutoRecoveryFlags extends CliFlags {
+
+ @Parameter(names = { "-e", "--enable" }, description = "Enable or disable auto recovery of under replicated "
+ + "ledgers.")
+ private boolean enable;
+
+ @Parameter(names = {"-s", "--status"}, description = "Check the auto recovery status.")
+ private boolean status;
+
+ }
+
+ @Override
+ public boolean apply(ServerConfiguration conf, AutoRecoveryFlags cmdFlags) {
+ try {
+ return handler(conf, cmdFlags);
+ } catch (MetadataException | ExecutionException e) {
+ throw new UncheckedExecutionException(e.getMessage(), e);
+ }
+ }
+
+ private boolean handler(ServerConfiguration conf, AutoRecoveryFlags flags)
+ throws MetadataException, ExecutionException {
+ MetadataDrivers.runFunctionWithLedgerManagerFactory(conf, mFactory -> {
+ try {
+ try (LedgerUnderreplicationManager underreplicationManager = mFactory
+ .newLedgerUnderreplicationManager()) {
+ if (flags.status) {
+ System.out.println("Autorecovery is " + (underreplicationManager.isLedgerReplicationEnabled()
+ ? "enabled." : "disabled."));
+ return null;
+ }
+ if (flags.enable) {
+ if (underreplicationManager.isLedgerReplicationEnabled()) {
+ LOG.warn("Autorecovery already enabled. Doing nothing");
+ } else {
+ LOG.info("Enabling autorecovery");
+ underreplicationManager.enableLedgerReplication();
+ }
+ } else {
+ if (!underreplicationManager.isLedgerReplicationEnabled()) {
+ LOG.warn("Autorecovery already disabled. Doing nothing");
+ } else {
+ LOG.info("Disabling autorecovery");
+ underreplicationManager.disableLedgerReplication();
+ }
+ }
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new UncheckedExecutionException(e);
+ } catch (KeeperException | ReplicationException e) {
+ throw new UncheckedExecutionException(e);
+ }
+ return null;
+ });
+ return true;
+ }
+}
diff --git a/tools/ledger/src/main/java/org/apache/bookkeeper/tools/cli/commands/AutoRecoveryCommandGroup.java b/tools/ledger/src/main/java/org/apache/bookkeeper/tools/cli/commands/AutoRecoveryCommandGroup.java
index 814976a1..aa4d7f4 100644
--- a/tools/ledger/src/main/java/org/apache/bookkeeper/tools/cli/commands/AutoRecoveryCommandGroup.java
+++ b/tools/ledger/src/main/java/org/apache/bookkeeper/tools/cli/commands/AutoRecoveryCommandGroup.java
@@ -20,6 +20,7 @@
import static org.apache.bookkeeper.tools.common.BKCommandCategories.CATEGORY_INFRA_SERVICE;
+import org.apache.bookkeeper.tools.cli.commands.autorecovery.ToggleCommand;
import org.apache.bookkeeper.tools.cli.commands.autorecovery.WhoIsAuditorCommand;
import org.apache.bookkeeper.tools.common.BKFlags;
import org.apache.bookkeeper.tools.framework.CliCommandGroup;
@@ -38,6 +39,7 @@
.withDescription(DESC)
.withCategory(CATEGORY_INFRA_SERVICE)
.addCommand(new WhoIsAuditorCommand())
+ .addCommand(new ToggleCommand())
.build();
public AutoRecoveryCommandGroup() {
diff --git a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/AutoRecoveryCommandTest.java b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/AutoRecoveryCommandTest.java
new file mode 100644
index 0000000..50c68d7
--- /dev/null
+++ b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/autorecovery/AutoRecoveryCommandTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.bookkeeper.tools.cli.commands.autorecovery;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.powermock.api.mockito.PowerMockito.mock;
+import static org.powermock.api.mockito.PowerMockito.when;
+
+import java.util.function.Function;
+import org.apache.bookkeeper.conf.ServerConfiguration;
+import org.apache.bookkeeper.meta.LedgerManagerFactory;
+import org.apache.bookkeeper.meta.LedgerUnderreplicationManager;
+import org.apache.bookkeeper.meta.MetadataDrivers;
+import org.apache.bookkeeper.replication.ReplicationException;
+import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase;
+import org.apache.zookeeper.KeeperException;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+
+/**
+ * Unit test for {@link ToggleCommand}.
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({ ToggleCommand.class, MetadataDrivers.class })
+public class AutoRecoveryCommandTest extends BookieCommandTestBase {
+
+ private LedgerManagerFactory ledgerManagerFactory;
+ private LedgerUnderreplicationManager ledgerUnderreplicationManager;
+
+ public AutoRecoveryCommandTest() {
+ super(3, 0);
+ }
+
+ @Override
+ public void setup() throws Exception {
+ super.setup();
+
+ PowerMockito.whenNew(ServerConfiguration.class).withNoArguments().thenReturn(conf);
+
+ ledgerManagerFactory = mock(LedgerManagerFactory.class);
+
+ PowerMockito.mockStatic(MetadataDrivers.class);
+ PowerMockito.doAnswer(invocationOnMock -> {
+ Function<LedgerManagerFactory, ?> function = invocationOnMock.getArgument(1);
+ function.apply(ledgerManagerFactory);
+ return true;
+ }).when(MetadataDrivers.class, "runFunctionWithLedgerManagerFactory", any(ServerConfiguration.class),
+ any(Function.class));
+
+ ledgerUnderreplicationManager = mock(LedgerUnderreplicationManager.class);
+ when(ledgerManagerFactory.newLedgerUnderreplicationManager()).thenReturn(ledgerUnderreplicationManager);
+ }
+
+ @Test
+ public void testWithEnable()
+ throws InterruptedException, ReplicationException.CompatibilityException, KeeperException,
+ ReplicationException.UnavailableException {
+ testCommand("-e");
+ verify(ledgerManagerFactory, times(1)).newLedgerUnderreplicationManager();
+ verify(ledgerUnderreplicationManager, times(1)).isLedgerReplicationEnabled();
+ }
+
+ @Test
+ public void testWithEnableLongArgs() throws ReplicationException.UnavailableException {
+ when(ledgerUnderreplicationManager.isLedgerReplicationEnabled()).thenReturn(false);
+ testCommand("--enable");
+ verify(ledgerUnderreplicationManager, times(1)).enableLedgerReplication();
+ }
+
+ @Test
+ public void testWithLook()
+ throws InterruptedException, ReplicationException.CompatibilityException, KeeperException,
+ ReplicationException.UnavailableException {
+ testCommand("s");
+ verify(ledgerManagerFactory, times(1)).newLedgerUnderreplicationManager();
+ verify(ledgerUnderreplicationManager, times(1)).isLedgerReplicationEnabled();
+ }
+
+ @Test
+ public void testWithNoArgs()
+ throws InterruptedException, ReplicationException.CompatibilityException, KeeperException,
+ ReplicationException.UnavailableException {
+ testCommand("");
+ verify(ledgerManagerFactory, times(1)).newLedgerUnderreplicationManager();
+ verify(ledgerUnderreplicationManager, times(1)).isLedgerReplicationEnabled();
+ }
+
+ @Test
+ public void testWithNoArgsDisable() throws ReplicationException.UnavailableException {
+ when(ledgerUnderreplicationManager.isLedgerReplicationEnabled()).thenReturn(true);
+ testCommand("");
+ verify(ledgerUnderreplicationManager, times(1)).isLedgerReplicationEnabled();
+ verify(ledgerUnderreplicationManager, times(1)).disableLedgerReplication();
+ }
+
+ private void testCommand(String... args) {
+ ToggleCommand cmd = new ToggleCommand();
+ Assert.assertTrue(cmd.apply(bkFlags, args));
+ }
+}