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());
+    }
+
+}

Reply via email to