This is an automated email from the ASF dual-hosted git repository.
shenwenbing pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git
The following commit(s) were added to refs/heads/master by this push:
new 4ebb34e77e [improve] Add ClusterInfo shell Command (#4004)
4ebb34e77e is described below
commit 4ebb34e77ede31f619d7d5d7e887b48ed4b08f60
Author: wenbingshen <[email protected]>
AuthorDate: Wed Jul 12 10:28:04 2023 +0800
[improve] Add ClusterInfo shell Command (#4004)
* Add ClusterInfo shell Command
* fix checkstyle
---
.../org/apache/bookkeeper/bookie/BookieShell.java | 35 ++++++
.../cli/commands/bookies/ClusterInfoCommand.java | 137 +++++++++++++++++++++
.../apache/bookkeeper/bookie/BookieShellTest.java | 14 +++
.../bookkeeper/bookie/ClusterInfoCommandTest.java | 63 ++++++++++
4 files changed, 249 insertions(+)
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 944b97e79d..c24be83282 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
@@ -73,6 +73,7 @@ import
org.apache.bookkeeper.tools.cli.commands.bookie.RebuildDBLedgersIndexComm
import
org.apache.bookkeeper.tools.cli.commands.bookie.RegenerateInterleavedStorageIndexFileCommand;
import org.apache.bookkeeper.tools.cli.commands.bookie.SanityTestCommand;
import
org.apache.bookkeeper.tools.cli.commands.bookie.UpdateBookieInLedgerCommand;
+import org.apache.bookkeeper.tools.cli.commands.bookies.ClusterInfoCommand;
import org.apache.bookkeeper.tools.cli.commands.bookies.DecommissionCommand;
import org.apache.bookkeeper.tools.cli.commands.bookies.EndpointInfoCommand;
import org.apache.bookkeeper.tools.cli.commands.bookies.InfoCommand;
@@ -148,6 +149,7 @@ public class BookieShell implements Tool {
static final String CMD_UPDATE_BOOKIE_IN_LEDGER = "updateBookieInLedger";
static final String CMD_DELETELEDGER = "deleteledger";
static final String CMD_BOOKIEINFO = "bookieinfo";
+ static final String CMD_CLUSTERINFO = "clusterinfo";
static final String CMD_ACTIVE_LEDGERS_ON_ENTRY_LOG_FILE = "activeledgers";
static final String CMD_DECOMMISSIONBOOKIE = "decommissionbookie";
static final String CMD_ENDPOINTINFO = "endpointinfo";
@@ -2239,6 +2241,38 @@ public class BookieShell implements Tool {
}
}
+ /*
+ * Command to exposes the current info about the cluster of bookies.
+ */
+ class ClusterInfoCmd extends MyCommand {
+ ClusterInfoCmd() {
+ super(CMD_CLUSTERINFO);
+ }
+
+ @Override
+ String getDescription() {
+ return "Exposes the current info about the cluster of bookies.";
+ }
+
+ @Override
+ String getUsage() {
+ return "clusterinfo";
+ }
+
+ @Override
+ Options getOptions() {
+ return opts;
+ }
+
+ @Override
+ int runCmd(CommandLine cmdLine) throws Exception {
+ ClusterInfoCommand cmd = new ClusterInfoCommand();
+ cmd.apply(bkConf, new CliFlags());
+ return 0;
+ }
+ }
+
+
final Map<String, Command> commands = new HashMap<>();
{
@@ -2272,6 +2306,7 @@ public class BookieShell implements Tool {
commands.put(CMD_UPDATE_BOOKIE_IN_LEDGER, new
UpdateBookieInLedgerCmd());
commands.put(CMD_DELETELEDGER, new DeleteLedgerCmd());
commands.put(CMD_BOOKIEINFO, new BookieInfoCmd());
+ commands.put(CMD_CLUSTERINFO, new ClusterInfoCmd());
commands.put(CMD_DECOMMISSIONBOOKIE, new DecommissionBookieCmd());
commands.put(CMD_ENDPOINTINFO, new EndpointInfoCmd());
commands.put(CMD_CONVERT_TO_DB_STORAGE, new ConvertToDbStorageCmd());
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/bookies/ClusterInfoCommand.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/bookies/ClusterInfoCommand.java
new file mode 100644
index 0000000000..e18daea933
--- /dev/null
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/bookies/ClusterInfoCommand.java
@@ -0,0 +1,137 @@
+/*
+ * 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.bookies;
+
+import static
org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithLedgerManagerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+import java.util.Iterator;
+import lombok.Data;
+import org.apache.bookkeeper.client.BKException;
+import org.apache.bookkeeper.client.BookKeeperAdmin;
+import org.apache.bookkeeper.common.util.JsonUtil;
+import org.apache.bookkeeper.conf.ClientConfiguration;
+import org.apache.bookkeeper.conf.ServerConfiguration;
+import org.apache.bookkeeper.meta.LedgerUnderreplicationManager;
+import org.apache.bookkeeper.meta.UnderreplicatedLedger;
+import org.apache.bookkeeper.net.BookieId;
+import org.apache.bookkeeper.tools.cli.helpers.BookieCommand;
+import org.apache.bookkeeper.tools.framework.CliFlags;
+import org.apache.bookkeeper.tools.framework.CliSpec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A bookie command to retrieve bookies cluster info.
+ */
+public class ClusterInfoCommand extends BookieCommand<CliFlags> {
+
+ private static final String NAME = "cluster-info";
+ private static final String DESC = "Exposes the current info about the
cluster of bookies";
+ private static final Logger LOG =
LoggerFactory.getLogger(ClusterInfoCommand.class);
+ private ClusterInfo info;
+
+ public ClusterInfoCommand() {
+ super(CliSpec.newBuilder()
+ .withName(NAME)
+ .withFlags(new CliFlags())
+ .withDescription(DESC)
+ .build());
+ }
+
+ /**
+ * POJO definition for the cluster info response.
+ */
+ @Data
+ public static class ClusterInfo {
+ private boolean auditorElected;
+ private String auditorId;
+ private boolean clusterUnderReplicated;
+ private boolean ledgerReplicationEnabled;
+ private int totalBookiesCount;
+ private int writableBookiesCount;
+ private int readonlyBookiesCount;
+ private int unavailableBookiesCount;
+ }
+
+ @Override
+ public boolean apply(ServerConfiguration conf, CliFlags cmdFlags) {
+
+ ClientConfiguration clientConfiguration = new
ClientConfiguration(conf);
+ try (BookKeeperAdmin admin = new BookKeeperAdmin(clientConfiguration))
{
+ LOG.info("Starting fill cluster info.");
+ info = new ClusterInfo();
+ fillUReplicatedInfo(info, conf);
+ fillAuditorInfo(info, admin);
+ fillBookiesInfo(info, admin);
+
+ LOG.info("--------- Cluster Info ---------");
+ LOG.info("{}", JsonUtil.toJson(info));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return true;
+ }
+
+ private void fillBookiesInfo(ClusterInfo info, BookKeeperAdmin bka) throws
BKException {
+ int totalBookiesCount = bka.getAllBookies().size();
+ int writableBookiesCount = bka.getAvailableBookies().size();
+ int readonlyBookiesCount = bka.getReadOnlyBookies().size();
+ int unavailableBookiesCount = totalBookiesCount - writableBookiesCount
- readonlyBookiesCount;
+
+ info.setTotalBookiesCount(totalBookiesCount);
+ info.setWritableBookiesCount(writableBookiesCount);
+ info.setReadonlyBookiesCount(readonlyBookiesCount);
+ info.setUnavailableBookiesCount(unavailableBookiesCount);
+ }
+
+ private void fillAuditorInfo(ClusterInfo info, BookKeeperAdmin bka) {
+ try {
+ BookieId currentAuditor = bka.getCurrentAuditor();
+ info.setAuditorElected(currentAuditor != null);
+ info.setAuditorId(currentAuditor == null ? "" :
currentAuditor.getId());
+ } catch (Exception e) {
+ LOG.error("Could not get Auditor info", e);
+ info.setAuditorElected(false);
+ info.setAuditorId("");
+ }
+ }
+
+ private void fillUReplicatedInfo(ClusterInfo info, ServerConfiguration
conf) throws Exception {
+ runFunctionWithLedgerManagerFactory(conf, mFactory -> {
+ try (LedgerUnderreplicationManager underreplicationManager =
+ mFactory.newLedgerUnderreplicationManager()) {
+ Iterator<UnderreplicatedLedger> iter =
underreplicationManager.listLedgersToRereplicate(null);
+
+ info.setClusterUnderReplicated(iter.hasNext());
+
info.setLedgerReplicationEnabled(underreplicationManager.isLedgerReplicationEnabled());
+ } catch (Exception e) {
+ throw new UncheckedExecutionException(e);
+ }
+ return null;
+ });
+ }
+
+ @VisibleForTesting
+ public ClusterInfo info() {
+ return info;
+ }
+}
diff --git
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieShellTest.java
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieShellTest.java
index d2fdf0662b..b40b9a4b6d 100644
---
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieShellTest.java
+++
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/BookieShellTest.java
@@ -50,6 +50,7 @@ import org.apache.bookkeeper.meta.MetadataBookieDriver;
import org.apache.bookkeeper.meta.MetadataDrivers;
import org.apache.bookkeeper.net.BookieId;
import org.apache.bookkeeper.tools.cli.commands.bookie.LastMarkCommand;
+import org.apache.bookkeeper.tools.cli.commands.bookies.ClusterInfoCommand;
import org.apache.bookkeeper.tools.cli.commands.bookies.ListBookiesCommand;
import org.apache.bookkeeper.tools.cli.commands.bookies.RecoverCommand;
import org.apache.bookkeeper.tools.cli.commands.client.SimpleTestCommand;
@@ -93,6 +94,7 @@ public class BookieShellTest {
private SimpleTestCommand mockSimpleTestCommand;
private ListBookiesCommand.Flags mockListBookiesFlags;
private ListBookiesCommand mockListBookiesCommand;
+ private ClusterInfoCommand mockClusterInfoCommand;
@Before
public void setup() throws Exception {
@@ -130,6 +132,11 @@ public class BookieShellTest {
.withArguments(mockListBookiesFlags)
.thenReturn(mockListBookiesCommand);
+ this.mockClusterInfoCommand = spy(new ClusterInfoCommand());
+ whenNew(ClusterInfoCommand.class)
+ .withNoArguments()
+ .thenReturn(mockClusterInfoCommand);
+
// construct the bookie shell.
this.shell = new
BookieShell(LedgerIdFormatter.LONG_LEDGERID_FORMATTER,
EntryFormatter.STRING_FORMATTER);
this.admin = PowerMockito.mock(BookKeeperAdmin.class);
@@ -458,4 +465,11 @@ public class BookieShellTest {
}));
}
+ @Test
+ public void testClusterInfoCmd() throws Exception {
+ doReturn(true).when(mockClusterInfoCommand).apply(same(shell.bkConf),
any(CliFlags.class));
+ shell.run(new String[]{ "clusterinfo" });
+ verifyNew(ClusterInfoCommand.class, times(1)).withNoArguments();
+ }
+
}
diff --git
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/ClusterInfoCommandTest.java
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/ClusterInfoCommandTest.java
new file mode 100644
index 0000000000..2e1bb55ce1
--- /dev/null
+++
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/ClusterInfoCommandTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.bookie;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.bookkeeper.conf.ServerConfiguration;
+import org.apache.bookkeeper.test.BookKeeperClusterTestCase;
+import org.apache.bookkeeper.tools.cli.commands.bookies.ClusterInfoCommand;
+import org.apache.bookkeeper.tools.framework.CliFlags;
+import org.junit.Test;
+
+/**
+ * Integration test of {@link
org.apache.bookkeeper.tools.cli.commands.bookies.ClusterInfoCommand}.
+ */
+public class ClusterInfoCommandTest extends BookKeeperClusterTestCase {
+
+ public ClusterInfoCommandTest() {
+ super(1);
+ }
+
+ @Test
+ public void testClusterInfo() throws Exception {
+ ClusterInfoCommand clusterInfoCommand = new ClusterInfoCommand();
+ final ServerConfiguration conf = confByIndex(0);
+
+ assertNull(clusterInfoCommand.info());
+
+ clusterInfoCommand.apply(conf, new CliFlags());
+
+ assertNotNull(clusterInfoCommand.info());
+ ClusterInfoCommand.ClusterInfo info = clusterInfoCommand.info();
+ assertEquals(1, info.getTotalBookiesCount());
+ assertEquals(1, info.getWritableBookiesCount());
+ assertEquals(0, info.getReadonlyBookiesCount());
+ assertEquals(0, info.getUnavailableBookiesCount());
+ assertFalse(info.isAuditorElected());
+ assertEquals("", info.getAuditorId());
+ assertFalse(info.isClusterUnderReplicated());
+ assertTrue(info.isLedgerReplicationEnabled());
+ }
+
+}