Skip to content

Commit

Permalink
[improve] Add ClusterInfo shell Command (#4004)
Browse files Browse the repository at this point in the history
* Add ClusterInfo shell Command

* fix checkstyle
  • Loading branch information
wenbingshen authored Jul 12, 2023
1 parent c967299 commit 4ebb34e
Show file tree
Hide file tree
Showing 4 changed files with 249 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
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;
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -2239,6 +2241,38 @@ int runCmd(CommandLine cmdLine) throws Exception {
}
}

/*
* 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<>();

{
Expand Down Expand Up @@ -2272,6 +2306,7 @@ int runCmd(CommandLine cmdLine) throws Exception {
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());
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -130,6 +132,11 @@ public void setup() throws Exception {
.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);
Expand Down Expand Up @@ -458,4 +465,11 @@ public void testForceAuditChecksWithAllArgs() throws Exception {
}));
}

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

}
Original file line number Diff line number Diff line change
@@ -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());
}

}

0 comments on commit 4ebb34e

Please sign in to comment.