This is an automated email from the ASF dual-hosted git repository.

sijie 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 0666215  Migrate command `updatecookie`
0666215 is described below

commit 066621507f2d40ea67aa7d7ddadbb9304db17993
Author: Yong Zhang <[email protected]>
AuthorDate: Fri Apr 19 08:30:26 2019 +0800

    Migrate command `updatecookie`
    
    Descriptions of the changes in this PR:
    
    #2059
    
    ### Description
    
    Provide some admin operation about cookie
    
    ```
    Command to update cookie
    
    Usage:  bkctl cookie admin [flags]
    
    Flags:
    
        -d, --delete
            Delete cookie both locally and in zooKeeper
    
        -e, --expandstorage
            Add new empty ledger/index directories
    
        -f, --force
            Force delete cookie
    
        -host, --hostname
            Expects config useHostNameAsBookieID=true as the option value
    
        -l, --list
            List paths of all the cookies present locally and on zooKeeper
    
    
        -h, --help
            Display help information
    ```
    
    ### Changes
    
    Update command `updatecookie` to `admin`
    
    
    Reviewers: Jia Zhai <[email protected]>
    
    This closes #2060 from zymap/command-updatecookie
---
 .../org/apache/bookkeeper/bookie/BookieShell.java  | 226 +-------------
 .../tools/cli/commands/cookie/AdminCommand.java    | 326 +++++++++++++++++++++
 .../tools/cli/commands/CookieCommandGroup.java     |   2 +
 .../cli/commands/cookie/AdminCommandTest.java      | 218 ++++++++++++++
 4 files changed, 559 insertions(+), 213 deletions(-)

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 700ce11..02a7391 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
@@ -19,11 +19,8 @@
 package org.apache.bookkeeper.bookie;
 
 import static 
org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithLedgerManagerFactory;
-import static 
org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithMetadataBookieDriver;
-import static 
org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithRegistrationManager;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.UncheckedExecutionException;
 import java.io.File;
 import java.io.IOException;
@@ -40,13 +37,10 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.stream.Collectors;
-import org.apache.bookkeeper.bookie.BookieException.CookieNotFoundException;
-import org.apache.bookkeeper.bookie.BookieException.InvalidCookieException;
 import org.apache.bookkeeper.client.LedgerEntry;
 import org.apache.bookkeeper.client.api.LedgerMetadata;
 import org.apache.bookkeeper.common.annotation.InterfaceAudience.Private;
@@ -86,18 +80,16 @@ import 
org.apache.bookkeeper.tools.cli.commands.bookies.NukeExistingClusterComma
 import org.apache.bookkeeper.tools.cli.commands.bookies.RecoverCommand;
 import org.apache.bookkeeper.tools.cli.commands.client.DeleteLedgerCommand;
 import org.apache.bookkeeper.tools.cli.commands.client.SimpleTestCommand;
+import org.apache.bookkeeper.tools.cli.commands.cookie.AdminCommand;
 import org.apache.bookkeeper.tools.cli.commands.cookie.CreateCookieCommand;
 import org.apache.bookkeeper.tools.cli.commands.cookie.DeleteCookieCommand;
 import org.apache.bookkeeper.tools.cli.commands.cookie.GenerateCookieCommand;
 import org.apache.bookkeeper.tools.cli.commands.cookie.GetCookieCommand;
 import org.apache.bookkeeper.tools.cli.commands.cookie.UpdateCookieCommand;
 import org.apache.bookkeeper.tools.framework.CliFlags;
-import org.apache.bookkeeper.util.BookKeeperConstants;
 import org.apache.bookkeeper.util.EntryFormatter;
-import org.apache.bookkeeper.util.IOUtils;
 import org.apache.bookkeeper.util.LedgerIdFormatter;
 import org.apache.bookkeeper.util.Tool;
-import org.apache.bookkeeper.versioning.Version;
 import org.apache.bookkeeper.versioning.Versioned;
 import org.apache.commons.cli.BasicParser;
 import org.apache.commons.cli.CommandLine;
@@ -111,7 +103,6 @@ import 
org.apache.commons.configuration.CompositeConfiguration;
 import org.apache.commons.configuration.PropertiesConfiguration;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang3.ArrayUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -1453,7 +1444,8 @@ public class BookieShell implements Tool {
 
         @Override
         int runCmd(CommandLine cmdLine) throws Exception {
-            int retValue = -1;
+            AdminCommand cmd = new AdminCommand();
+            AdminCommand.AdminFlags flags = new AdminCommand.AdminFlags();
             Option[] options = cmdLine.getOptions();
             if (options.length != 1) {
                 LOG.error("Invalid command!");
@@ -1474,214 +1466,22 @@ public class BookieShell implements Tool {
                     return -1;
                 }
                 boolean useHostName = getOptionalValue(bookieId, HOSTNAME);
-                if (!bkConf.getUseHostNameAsBookieID() && useHostName) {
-                    LOG.error(
-                            "Expects config useHostNameAsBookieID=true as the 
option value passed is 'hostname'");
-                    return -1;
-                } else if (bkConf.getUseHostNameAsBookieID() && !useHostName) {
-                    LOG.error("Expects configuration 
useHostNameAsBookieID=false as the option value passed is 'ip'");
-                    return -1;
-                }
-                retValue = updateBookieIdInCookie(bookieId, useHostName);
-            } else if (thisCommandOption.getLongOpt().equals(EXPANDSTORAGE)) {
-                bkConf.setAllowStorageExpansion(true);
-                return expandStorage();
-            } else if (thisCommandOption.getLongOpt().equals(LIST)) {
-                return listOrDeleteCookies(false, false);
-            } else if (thisCommandOption.getLongOpt().equals(DELETE)) {
+                flags.hostname(useHostName);
+                flags.ip(!useHostName);
+            }
+            
flags.expandstorage(thisCommandOption.getLongOpt().equals(EXPANDSTORAGE));
+            flags.list(thisCommandOption.getLongOpt().equals(LIST));
+            flags.delete(thisCommandOption.getLongOpt().equals(DELETE));
+            if (thisCommandOption.getLongOpt().equals(DELETE)) {
                 boolean force = false;
                 String optionValue = thisCommandOption.getValue();
                 if (!StringUtils.isEmpty(optionValue) && 
optionValue.equals(FORCE)) {
                     force = true;
                 }
-                return listOrDeleteCookies(true, force);
-            } else {
-                LOG.error("Invalid command!");
-                this.printUsage();
-                return -1;
+                flags.force(force);
             }
-            return retValue;
-        }
-
-        private int updateBookieIdInCookie(final String bookieId, final 
boolean useHostname)
-                throws Exception {
-            return runFunctionWithRegistrationManager(bkConf, rm -> {
-                try {
-                    ServerConfiguration conf = new ServerConfiguration(bkConf);
-                    String newBookieId = 
Bookie.getBookieAddress(conf).toString();
-                    // read oldcookie
-                    Versioned<Cookie> oldCookie = null;
-                    try {
-                        conf.setUseHostNameAsBookieID(!useHostname);
-                        oldCookie = Cookie.readFromRegistrationManager(rm, 
conf);
-                    } catch (CookieNotFoundException nne) {
-                        LOG.error("Either cookie already updated with 
UseHostNameAsBookieID={} or no cookie exists!",
-                            useHostname, nne);
-                        return -1;
-                    }
-                    Cookie newCookie = 
Cookie.newBuilder(oldCookie.getValue()).setBookieHost(newBookieId).build();
-                    boolean hasCookieUpdatedInDirs = verifyCookie(newCookie, 
journalDirectories[0]);
-                    for (File dir : ledgerDirectories) {
-                        hasCookieUpdatedInDirs &= verifyCookie(newCookie, dir);
-                    }
-                    if (indexDirectories != ledgerDirectories) {
-                        for (File dir : indexDirectories) {
-                            hasCookieUpdatedInDirs &= verifyCookie(newCookie, 
dir);
-                        }
-                    }
-
-                    if (hasCookieUpdatedInDirs) {
-                        try {
-                            conf.setUseHostNameAsBookieID(useHostname);
-                            Cookie.readFromRegistrationManager(rm, conf);
-                            // since newcookie exists, just do cleanup of 
oldcookie and return
-                            conf.setUseHostNameAsBookieID(!useHostname);
-                            
oldCookie.getValue().deleteFromRegistrationManager(rm, conf, 
oldCookie.getVersion());
-                            return 0;
-                        } catch (CookieNotFoundException nne) {
-                            if (LOG.isDebugEnabled()) {
-                                LOG.debug("Ignoring, cookie will be written to 
zookeeper");
-                            }
-                        }
-                    } else {
-                        // writes newcookie to local dirs
-                        for (File journalDirectory : journalDirectories) {
-                            newCookie.writeToDirectory(journalDirectory);
-                            LOG.info("Updated cookie file present in 
journalDirectory {}", journalDirectory);
-                        }
-                        for (File dir : ledgerDirectories) {
-                            newCookie.writeToDirectory(dir);
-                        }
-                        LOG.info("Updated cookie file present in 
ledgerDirectories {}", (Object) ledgerDirectories);
-                        if (ledgerDirectories != indexDirectories) {
-                            for (File dir : indexDirectories) {
-                                newCookie.writeToDirectory(dir);
-                            }
-                            LOG.info("Updated cookie file present in 
indexDirectories {}", (Object) indexDirectories);
-                        }
-                    }
-                    // writes newcookie to zookeeper
-                    conf.setUseHostNameAsBookieID(useHostname);
-                    newCookie.writeToRegistrationManager(rm, conf, 
Version.NEW);
-
-                    // delete oldcookie
-                    conf.setUseHostNameAsBookieID(!useHostname);
-                    oldCookie.getValue().deleteFromRegistrationManager(rm, 
conf, oldCookie.getVersion());
-                    return 0;
-                } catch (IOException | BookieException ioe) {
-                    LOG.error("IOException during cookie updation!", ioe);
-                    return -1;
-                }
-            });
-        }
-
-        private int expandStorage() throws Exception {
-            return runFunctionWithMetadataBookieDriver(bkConf, driver -> {
-                List<File> allLedgerDirs = Lists.newArrayList();
-                allLedgerDirs.addAll(Arrays.asList(ledgerDirectories));
-                if (indexDirectories != ledgerDirectories) {
-                    allLedgerDirs.addAll(Arrays.asList(indexDirectories));
-                }
-
-                try {
-                    Bookie.checkEnvironmentWithStorageExpansion(
-                        bkConf, driver, Arrays.asList(journalDirectories), 
allLedgerDirs);
-                    return 0;
-                } catch (BookieException e) {
-                    LOG.error("Exception while updating cookie for storage 
expansion", e);
-                    return -1;
-                }
-            });
-        }
-
-        private boolean verifyCookie(Cookie oldCookie, File dir) throws 
IOException {
-            try {
-                Cookie cookie = Cookie.readFromDirectory(dir);
-                cookie.verify(oldCookie);
-            } catch (InvalidCookieException e) {
-                return false;
-            }
-            return true;
-        }
-
-        private int listOrDeleteCookies(boolean delete, boolean force) throws 
Exception {
-            BookieSocketAddress bookieAddress = 
Bookie.getBookieAddress(bkConf);
-            File[] journalDirs = bkConf.getJournalDirs();
-            File[] ledgerDirs = bkConf.getLedgerDirs();
-            File[] indexDirs = bkConf.getIndexDirs();
-            File[] allDirs = ArrayUtils.addAll(journalDirs, ledgerDirs);
-            if (indexDirs != null) {
-                allDirs = ArrayUtils.addAll(allDirs, indexDirs);
-            }
-
-            File[] allCurDirs = Bookie.getCurrentDirectories(allDirs);
-            List<File> allVersionFiles = new LinkedList<File>();
-            File versionFile;
-            for (File curDir : allCurDirs) {
-                versionFile = new File(curDir, 
BookKeeperConstants.VERSION_FILENAME);
-                if (versionFile.exists()) {
-                    allVersionFiles.add(versionFile);
-                }
-            }
-
-            if (!allVersionFiles.isEmpty()) {
-                if (delete) {
-                    boolean confirm = force;
-                    if (!confirm) {
-                        confirm = IOUtils.confirmPrompt("Are you sure you want 
to delete Cookies locally?");
-                    }
-                    if (confirm) {
-                        for (File verFile : allVersionFiles) {
-                            if (!verFile.delete()) {
-                                LOG.error(
-                                        "Failed to delete Local cookie file 
{}. So aborting deletecookie of Bookie: {}",
-                                        verFile, bookieAddress);
-                                return -1;
-                            }
-                        }
-                        LOG.info("Deleted Local Cookies of Bookie: {}", 
bookieAddress);
-                    } else {
-                        LOG.info("Skipping deleting local Cookies of Bookie: 
{}", bookieAddress);
-                    }
-                } else {
-                    LOG.info("Listing local Cookie Files of Bookie: {}", 
bookieAddress);
-                    for (File verFile : allVersionFiles) {
-                        LOG.info(verFile.getCanonicalPath());
-                    }
-                }
-            } else {
-                LOG.info("No local cookies for Bookie: {}", bookieAddress);
-            }
-
-            return runFunctionWithRegistrationManager(bkConf, rm -> {
-                try {
-                    Versioned<Cookie> cookie = null;
-                    try {
-                        cookie = Cookie.readFromRegistrationManager(rm, 
bookieAddress);
-                    } catch (CookieNotFoundException nne) {
-                        LOG.info("No cookie for {} in metadata store", 
bookieAddress);
-                        return 0;
-                    }
-
-                    if (delete) {
-                        boolean confirm = force;
-                        if (!confirm) {
-                            confirm = IOUtils.confirmPrompt(
-                                "Are you sure you want to delete Cookies from 
metadata store?");
-                        }
-
-                        if (confirm) {
-                            
cookie.getValue().deleteFromRegistrationManager(rm, bkConf, 
cookie.getVersion());
-                            LOG.info("Deleted Cookie from metadata store for 
Bookie: {}", bookieAddress);
-                        } else {
-                            LOG.info("Skipping deleting cookie from metadata 
store for Bookie: {}", bookieAddress);
-                        }
-                    }
-                } catch (BookieException | IOException e) {
-                    return -1;
-                }
-                return 0;
-            });
+            boolean result = cmd.apply(bkConf, flags);
+            return (result) ? 0 : -1;
         }
     }
 
diff --git 
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/cookie/AdminCommand.java
 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/cookie/AdminCommand.java
new file mode 100644
index 0000000..dce11ce
--- /dev/null
+++ 
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/tools/cli/commands/cookie/AdminCommand.java
@@ -0,0 +1,326 @@
+/*
+ * 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.cookie;
+
+import static 
org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithMetadataBookieDriver;
+import static 
org.apache.bookkeeper.meta.MetadataDrivers.runFunctionWithRegistrationManager;
+
+import com.beust.jcommander.Parameter;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import org.apache.bookkeeper.bookie.Bookie;
+import org.apache.bookkeeper.bookie.BookieException;
+import org.apache.bookkeeper.bookie.Cookie;
+import org.apache.bookkeeper.conf.ServerConfiguration;
+import org.apache.bookkeeper.net.BookieSocketAddress;
+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.bookkeeper.util.BookKeeperConstants;
+import org.apache.bookkeeper.util.IOUtils;
+import org.apache.bookkeeper.versioning.Version;
+import org.apache.bookkeeper.versioning.Versioned;
+import org.apache.commons.lang3.ArrayUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Command to update cookie.
+ */
+public class AdminCommand extends BookieCommand<AdminCommand.AdminFlags> {
+
+    static final Logger LOG = LoggerFactory.getLogger(AdminCommand.class);
+
+    private static final String NAME = "admin";
+    private static final String DESC = "Command to update cookie";
+
+    private File[] journalDirectories;
+    private File[] ledgerDirectories;
+    private File[] indexDirectories;
+
+    public AdminCommand() {
+        this(new AdminFlags());
+    }
+
+    private AdminCommand(AdminFlags flags) {
+        
super(CliSpec.<AdminFlags>newBuilder().withName(NAME).withDescription(DESC).withFlags(flags).build());
+    }
+
+    /**
+     * Flags for admin command.
+     */
+    @Accessors(fluent = true)
+    @Setter
+    public static class AdminFlags extends CliFlags {
+
+        @Parameter(names = { "-host",
+            "--hostname" }, description = "Expects config 
useHostNameAsBookieID=true as the option value")
+        private boolean hostname;
+
+        @Parameter(names = { "-p", "-ip" },
+            description = "Expects config useHostNameAsBookieID=false as the 
option value")
+        private boolean ip;
+
+        @Parameter(names = { "-e", "--expandstorage" }, description = "Add new 
empty ledger/index directories")
+        private boolean expandstorage;
+
+        @Parameter(names = { "-l", "--list" }, description = "List paths of 
all the cookies present locally and on "
+                                                             + "zooKeeper")
+        private boolean list;
+
+        @Parameter(names = { "-d", "--delete" }, description = "Delete cookie 
both locally and in zooKeeper")
+        private boolean delete;
+
+        @Parameter(names = {"-f", "--force"}, description = "Force delete 
cookie")
+        private boolean force;
+
+    }
+
+    @Override
+    public boolean apply(ServerConfiguration conf, AdminFlags cmdFlags) {
+        initDirectory(conf);
+        try {
+            return update(conf, cmdFlags);
+        } catch (Exception e) {
+            throw new UncheckedExecutionException(e.getMessage(), e);
+        }
+    }
+
+    private void initDirectory(ServerConfiguration bkConf) {
+        this.journalDirectories = 
Bookie.getCurrentDirectories(bkConf.getJournalDirs());
+        this.ledgerDirectories = 
Bookie.getCurrentDirectories(bkConf.getLedgerDirs());
+        if (null == bkConf.getIndexDirs()) {
+            this.indexDirectories = this.ledgerDirectories;
+        } else {
+            this.indexDirectories = 
Bookie.getCurrentDirectories(bkConf.getIndexDirs());
+        }
+    }
+
+    private boolean update(ServerConfiguration conf, AdminFlags flags) throws 
Exception {
+        boolean useHostName = flags.hostname;
+        if (flags.hostname || flags.ip) {
+            if (!conf.getUseHostNameAsBookieID() && useHostName) {
+                LOG.error("Expects configuration useHostNameAsBookieID=true as 
the option value");
+                return false;
+            } else if (conf.getUseHostNameAsBookieID() && !useHostName) {
+                LOG.error("Expects configuration useHostNameAsBookieID=false 
as the option value");
+                return false;
+            }
+            return updateBookieIdInCookie(conf, flags.hostname);
+        } else if (flags.expandstorage) {
+            conf.setAllowStorageExpansion(true);
+            return expandStorage(conf);
+        } else if (flags.list) {
+            return listOrDeleteCookies(conf, false, false);
+        } else if (flags.delete) {
+            return listOrDeleteCookies(conf, true, flags.force);
+        } else {
+            LOG.error("Invalid command !");
+            usage();
+            return false;
+        }
+    }
+
+    private boolean updateBookieIdInCookie(ServerConfiguration bkConf, final 
boolean useHostname)
+        throws Exception {
+        return runFunctionWithRegistrationManager(bkConf, rm -> {
+            try {
+                ServerConfiguration conf = new ServerConfiguration(bkConf);
+                String newBookieId = Bookie.getBookieAddress(conf).toString();
+                // read oldcookie
+                Versioned<Cookie> oldCookie = null;
+                try {
+                    conf.setUseHostNameAsBookieID(!useHostname);
+                    oldCookie = Cookie.readFromRegistrationManager(rm, conf);
+                } catch (BookieException.CookieNotFoundException nne) {
+                    LOG.error("Either cookie already updated with 
UseHostNameAsBookieID={} or no cookie exists!",
+                              useHostname, nne);
+                    return false;
+                }
+                Cookie newCookie = 
Cookie.newBuilder(oldCookie.getValue()).setBookieHost(newBookieId).build();
+
+                boolean hasCookieUpdatedInDirs = verifyCookie(newCookie, 
journalDirectories[0]);
+                for (File dir : ledgerDirectories) {
+                    hasCookieUpdatedInDirs &= verifyCookie(newCookie, dir);
+                }
+                if (indexDirectories != ledgerDirectories) {
+                    for (File dir : indexDirectories) {
+                        hasCookieUpdatedInDirs &= verifyCookie(newCookie, dir);
+                    }
+                }
+
+                if (hasCookieUpdatedInDirs) {
+                    try {
+                        conf.setUseHostNameAsBookieID(useHostname);
+                        Cookie.readFromRegistrationManager(rm, conf);
+                        // since newcookie exists, just do cleanup of 
oldcookie and return
+                        conf.setUseHostNameAsBookieID(!useHostname);
+                        oldCookie.getValue().deleteFromRegistrationManager(rm, 
conf, oldCookie.getVersion());
+                        return true;
+                    } catch (BookieException.CookieNotFoundException nne) {
+                        if (LOG.isDebugEnabled()) {
+                            LOG.debug("Ignoring, cookie will be written to 
zookeeper");
+                        }
+                    }
+                } else {
+                    // writes newcookie to local dirs
+                    for (File journalDirectory : journalDirectories) {
+                        newCookie.writeToDirectory(journalDirectory);
+                        LOG.info("Updated cookie file present in 
journalDirectory {}", journalDirectory);
+                    }
+                    for (File dir : ledgerDirectories) {
+                        newCookie.writeToDirectory(dir);
+                    }
+                    LOG.info("Updated cookie file present in ledgerDirectories 
{}", (Object) ledgerDirectories);
+                    if (ledgerDirectories != indexDirectories) {
+                        for (File dir : indexDirectories) {
+                            newCookie.writeToDirectory(dir);
+                        }
+                        LOG.info("Updated cookie file present in 
indexDirectories {}", (Object) indexDirectories);
+                    }
+                }
+                // writes newcookie to zookeeper
+                conf.setUseHostNameAsBookieID(useHostname);
+                newCookie.writeToRegistrationManager(rm, conf, Version.NEW);
+
+                // delete oldcookie
+                conf.setUseHostNameAsBookieID(!useHostname);
+                oldCookie.getValue().deleteFromRegistrationManager(rm, conf, 
oldCookie.getVersion());
+                return true;
+            } catch (IOException | BookieException ioe) {
+                LOG.error("IOException during cookie updation!", ioe);
+                return false;
+            }
+        });
+    }
+
+    private boolean verifyCookie(Cookie oldCookie, File dir) throws 
IOException {
+        try {
+            Cookie cookie = Cookie.readFromDirectory(dir);
+            cookie.verify(oldCookie);
+        } catch (BookieException.InvalidCookieException e) {
+            return false;
+        }
+        return true;
+    }
+
+    private boolean expandStorage(ServerConfiguration bkConf) throws Exception 
{
+        return runFunctionWithMetadataBookieDriver(bkConf, driver -> {
+            List<File> allLedgerDirs = Lists.newArrayList();
+            allLedgerDirs.addAll(Arrays.asList(ledgerDirectories));
+            if (indexDirectories != ledgerDirectories) {
+                allLedgerDirs.addAll(Arrays.asList(indexDirectories));
+            }
+
+            try {
+                Bookie.checkEnvironmentWithStorageExpansion(bkConf, driver, 
Arrays.asList(journalDirectories),
+                                                            allLedgerDirs);
+                return true;
+            } catch (BookieException e) {
+                LOG.error("Exception while updating cookie for storage 
expansion", e);
+                return false;
+            }
+        });
+    }
+
+    private boolean listOrDeleteCookies(ServerConfiguration bkConf, boolean 
delete, boolean force) throws Exception {
+        BookieSocketAddress bookieAddress = Bookie.getBookieAddress(bkConf);
+        File[] journalDirs = bkConf.getJournalDirs();
+        File[] ledgerDirs = bkConf.getLedgerDirs();
+        File[] indexDirs = bkConf.getIndexDirs();
+        File[] allDirs = ArrayUtils.addAll(journalDirs, ledgerDirs);
+        if (indexDirs != null) {
+            allDirs = ArrayUtils.addAll(allDirs, indexDirs);
+        }
+
+        File[] allCurDirs = Bookie.getCurrentDirectories(allDirs);
+        List<File> allVersionFiles = new LinkedList<File>();
+        File versionFile;
+        for (File curDir : allCurDirs) {
+            versionFile = new File(curDir, 
BookKeeperConstants.VERSION_FILENAME);
+            if (versionFile.exists()) {
+                allVersionFiles.add(versionFile);
+            }
+        }
+
+        if (!allVersionFiles.isEmpty()) {
+            if (delete) {
+                boolean confirm = force;
+                if (!confirm) {
+                    confirm = IOUtils.confirmPrompt("Are you sure you want to 
delete Cookies locally?");
+                }
+                if (confirm) {
+                    for (File verFile : allVersionFiles) {
+                        if (!verFile.delete()) {
+                            LOG.error("Failed to delete Local cookie file {}. 
So aborting deletecookie of Bookie: {}",
+                                      verFile, bookieAddress);
+                            return false;
+                        }
+                    }
+                    LOG.info("Deleted Local Cookies of Bookie: {}", 
bookieAddress);
+                } else {
+                    LOG.info("Skipping deleting local Cookies of Bookie: {}", 
bookieAddress);
+                }
+            } else {
+                LOG.info("Listing local Cookie Files of Bookie: {}", 
bookieAddress);
+                for (File verFile : allVersionFiles) {
+                    LOG.info(verFile.getCanonicalPath());
+                }
+            }
+        } else {
+            LOG.info("No local cookies for Bookie: {}", bookieAddress);
+        }
+
+        return runFunctionWithRegistrationManager(bkConf, rm -> {
+            try {
+                Versioned<Cookie> cookie = null;
+                try {
+                    cookie = Cookie.readFromRegistrationManager(rm, 
bookieAddress);
+                } catch (BookieException.CookieNotFoundException nne) {
+                    LOG.info("No cookie for {} in metadata store", 
bookieAddress);
+                    return true;
+                }
+
+                if (delete) {
+                    boolean confirm = force;
+                    if (!confirm) {
+                        confirm = IOUtils.confirmPrompt("Are you sure you want 
to delete Cookies from metadata store?");
+                    }
+
+                    if (confirm) {
+                        cookie.getValue().deleteFromRegistrationManager(rm, 
bkConf, cookie.getVersion());
+                        LOG.info("Deleted Cookie from metadata store for 
Bookie: {}", bookieAddress);
+                    } else {
+                        LOG.info("Skipping deleting cookie from metadata store 
for Bookie: {}", bookieAddress);
+                    }
+                }
+            } catch (BookieException | IOException e) {
+                return false;
+            }
+            return true;
+        });
+    }
+}
diff --git 
a/tools/ledger/src/main/java/org/apache/bookkeeper/tools/cli/commands/CookieCommandGroup.java
 
b/tools/ledger/src/main/java/org/apache/bookkeeper/tools/cli/commands/CookieCommandGroup.java
index 3dded4e..83dfc26 100644
--- 
a/tools/ledger/src/main/java/org/apache/bookkeeper/tools/cli/commands/CookieCommandGroup.java
+++ 
b/tools/ledger/src/main/java/org/apache/bookkeeper/tools/cli/commands/CookieCommandGroup.java
@@ -20,6 +20,7 @@
 package org.apache.bookkeeper.tools.cli.commands;
 
 import org.apache.bookkeeper.tools.cli.BKCtl;
+import org.apache.bookkeeper.tools.cli.commands.cookie.AdminCommand;
 import org.apache.bookkeeper.tools.cli.commands.cookie.CreateCookieCommand;
 import org.apache.bookkeeper.tools.cli.commands.cookie.DeleteCookieCommand;
 import org.apache.bookkeeper.tools.cli.commands.cookie.GenerateCookieCommand;
@@ -46,6 +47,7 @@ public class CookieCommandGroup extends 
CliCommandGroup<BKFlags> {
         .addCommand(new GetCookieCommand())
         .addCommand(new UpdateCookieCommand())
         .addCommand(new GenerateCookieCommand())
+        .addCommand(new AdminCommand())
         .build();
 
     public CookieCommandGroup() {
diff --git 
a/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/AdminCommandTest.java
 
b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/AdminCommandTest.java
new file mode 100644
index 0000000..9f39867
--- /dev/null
+++ 
b/tools/ledger/src/test/java/org/apache/bookkeeper/tools/cli/commands/cookie/AdminCommandTest.java
@@ -0,0 +1,218 @@
+/*
+ * 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.cookie;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.verify;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
+import static org.powermock.api.mockito.PowerMockito.mock;
+import static org.powermock.api.mockito.PowerMockito.verifyNew;
+import static org.powermock.api.mockito.PowerMockito.when;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.util.function.Function;
+import org.apache.bookkeeper.bookie.Bookie;
+import org.apache.bookkeeper.bookie.BookieException;
+import org.apache.bookkeeper.bookie.Cookie;
+import org.apache.bookkeeper.conf.AbstractConfiguration;
+import org.apache.bookkeeper.conf.ServerConfiguration;
+import org.apache.bookkeeper.discover.RegistrationManager;
+import org.apache.bookkeeper.meta.MetadataBookieDriver;
+import org.apache.bookkeeper.meta.MetadataDrivers;
+import org.apache.bookkeeper.net.BookieSocketAddress;
+import org.apache.bookkeeper.tools.cli.helpers.BookieCommandTestBase;
+import org.apache.bookkeeper.util.BookKeeperConstants;
+import org.apache.bookkeeper.versioning.Version;
+import org.apache.bookkeeper.versioning.Versioned;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+/**
+ * Unit test for {@link AdminCommand}.
+ */
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({ AdminCommand.class, MetadataDrivers.class, Cookie.class, 
Bookie.class, RegistrationManager.class })
+public class AdminCommandTest extends BookieCommandTestBase {
+
+    @Mock
+    private ServerConfiguration serverConfiguration;
+
+    @Mock
+    private Versioned<Cookie> cookieVersioned;
+
+    @Mock
+    private Cookie cookie;
+
+    @Mock
+    private BookieSocketAddress bookieSocketAddress;
+
+    public AdminCommandTest() throws IOException {
+        super(3, 3);
+    }
+
+    public void createIndex() throws IOException {
+        String[] indexDirs = new String[3];
+        for (int i = 0; i < indexDirs.length; i++) {
+            File dir = this.testDir.newFile();
+            dir.mkdirs();
+            indexDirs[i] = dir.getAbsolutePath();
+        }
+        this.conf.setIndexDirName(indexDirs);
+
+    }
+    @Override
+    public void setup() throws Exception {
+        super.setup();
+        createIndex();
+
+        
PowerMockito.whenNew(ServerConfiguration.class).withNoArguments().thenReturn(conf);
+        PowerMockito.mockStatic(MetadataDrivers.class);
+        
PowerMockito.whenNew(ServerConfiguration.class).withParameterTypes(AbstractConfiguration.class)
+                    .withArguments(eq(conf)).thenReturn(serverConfiguration);
+        PowerMockito.mockStatic(Cookie.class);
+        PowerMockito.mockStatic(MetadataDrivers.class);
+        PowerMockito.mockStatic(Bookie.class);
+
+        mockUpdateBookieIdInCookie();
+        mockVerifyCookie();
+        mockInitDirecotory();
+        mockExpandStorage();
+        mockListOrDeleteCookies();
+
+    }
+
+    private void mockInitDirecotory() throws IOException {
+        File[] files = new File[1];
+        files[0] = testDir.getRoot();
+        testDir.newFile(BookKeeperConstants.VERSION_FILENAME);
+        
PowerMockito.when(Bookie.getCurrentDirectories(any())).thenReturn(files);
+    }
+
+    private void mockUpdateBookieIdInCookie() throws Exception {
+        RegistrationManager registrationManager = 
mock(RegistrationManager.class);
+        PowerMockito.doAnswer(invocationOnMock -> {
+            Function<RegistrationManager, ?> f = 
invocationOnMock.getArgument(1);
+            f.apply(registrationManager);
+            return true;
+        }).when(MetadataDrivers.class, "runFunctionWithRegistrationManager", 
any(ServerConfiguration.class),
+                any(Function.class));
+
+        
PowerMockito.when(Bookie.getBookieAddress(eq(serverConfiguration))).thenReturn(bookieSocketAddress);
+        when(bookieSocketAddress.toString()).thenReturn("1");
+        
PowerMockito.when(Cookie.readFromRegistrationManager(eq(registrationManager), 
eq(serverConfiguration)))
+                    .thenReturn(cookieVersioned);
+        
PowerMockito.when(Cookie.readFromRegistrationManager(eq(registrationManager), 
eq(bookieSocketAddress)))
+                    .thenReturn(cookieVersioned);
+        when(cookieVersioned.getValue()).thenReturn(cookie);
+        Cookie.Builder builder = mock(Cookie.Builder.class);
+        PowerMockito.when(Cookie.newBuilder(eq(cookie))).thenReturn(builder);
+        
PowerMockito.when(builder.setBookieHost(anyString())).thenReturn(builder);
+        when(builder.build()).thenReturn(cookie);
+
+        
PowerMockito.when(serverConfiguration.setUseHostNameAsBookieID(anyBoolean())).thenReturn(serverConfiguration);
+        
PowerMockito.when(Cookie.readFromRegistrationManager(eq(registrationManager), 
eq(serverConfiguration)))
+                    .thenReturn(cookieVersioned);
+
+        Version version = mock(Version.class);
+        when(cookieVersioned.getVersion()).thenReturn(version);
+        when(cookieVersioned.getValue()).thenReturn(cookie);
+        doNothing().when(cookie)
+                   .deleteFromRegistrationManager(eq(registrationManager), 
eq(serverConfiguration), eq(version));
+
+        doNothing().when(cookie).writeToDirectory(any(File.class));
+        doNothing().when(cookie)
+                   .writeToRegistrationManager(eq(registrationManager), 
eq(serverConfiguration), eq(Version.NEW));
+
+        doNothing().when(cookie)
+                   .deleteFromRegistrationManager(eq(registrationManager), 
any(ServerConfiguration.class), eq(version));
+    }
+
+    private void mockVerifyCookie() throws IOException, 
BookieException.InvalidCookieException {
+        
PowerMockito.when(Cookie.readFromDirectory(any(File.class))).thenReturn(cookie);
+        doNothing().when(cookie).verify(any(Cookie.class));
+    }
+
+    private void mockExpandStorage() throws Exception {
+        MetadataBookieDriver metadataBookieDriver = 
mock(MetadataBookieDriver.class);
+        PowerMockito.doAnswer(invocationOnMock -> {
+            Function<MetadataBookieDriver, ?> f = 
invocationOnMock.getArgument(1);
+            f.apply(metadataBookieDriver);
+            return true;
+        }).when(MetadataDrivers.class, "runFunctionWithMetadataBookieDriver", 
any(ServerConfiguration.class),
+                any(Function.class));
+        PowerMockito.doNothing()
+                    .when(Bookie.class, 
"checkEnvironmentWithStorageExpansion", any(ServerConfiguration.class),
+                          eq(metadataBookieDriver), any(), any());
+    }
+
+    private void mockListOrDeleteCookies() throws UnknownHostException {
+
+        
when(Bookie.getBookieAddress(any(ServerConfiguration.class))).thenReturn(bookieSocketAddress);
+    }
+
+    @Test
+    public void testWithoutAnyFlags() {
+        AdminCommand cmd = new AdminCommand();
+        Assert.assertFalse(cmd.apply(bkFlags, new String[] {""}));
+    }
+
+    @Test
+    public void testWithHostName() throws Exception {
+        conf.setUseHostNameAsBookieID(true);
+        testCommand("-host");
+        verifyNew(ServerConfiguration.class, times(1)).withArguments(eq(conf));
+        verify(serverConfiguration, 
times(3)).setUseHostNameAsBookieID(anyBoolean());
+
+        verify(cookie, times(2)).verify(any(Cookie.class));
+    }
+
+    @Test
+    public void testWithExpand() {
+        testCommand("-e");
+    }
+
+    @Test
+    public void testWithList() {
+        testCommand("-l");
+    }
+
+    @Test
+    public void testWithDelete() throws BookieException {
+        testCommand("-d", "-f");
+        verify(cookie, times(1))
+            .deleteFromRegistrationManager(any(RegistrationManager.class), 
any(ServerConfiguration.class),
+                                           any(Version.class));
+    }
+
+    private void testCommand(String... args) {
+        AdminCommand cmd = new AdminCommand();
+        Assert.assertTrue(cmd.apply(bkFlags, args));
+    }
+}

Reply via email to