This is an automated email from the ASF dual-hosted git repository. jmclean pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push: new fb78e6582 [#5826] fix(CLI): Fix Dropping a metalake via the Gravitino CLI gives an "in use" exception (#5907) fb78e6582 is described below commit fb78e6582e89a54218fb33c1edb6d9ac3c2489b2 Author: Lord of Abyss <103809695+abyss-l...@users.noreply.github.com> AuthorDate: Tue Dec 24 05:34:39 2024 +0800 [#5826] fix(CLI): Fix Dropping a metalake via the Gravitino CLI gives an "in use" exception (#5907) ### What changes were proposed in this pull request? When attempting to drop a metalake via the Gravitino CLI, an "in use" exception is raised. If the metalake is currently in use, the system should provide additional hints or details to help the user identify the issue. Additionally, it would be beneficial to add enable and disable commands to the client. These commands would allow users to enable or disable a catalog or metalake directly through the client interface. #### enable command - `metalake update -m demo_metalake --enable` : enable a metalake - `metalake update -m demo_metalake --enable --all`: enable a metalake and all catalogs in this metalake. - `catalog update -m demo_metalake --name Hive_catalog --enable`: enable a catalog - `catalog update -m demo_metalake --name Hive_catalog --enable --all`: enable a catalog and it's metalake #### disable command - `metalake update -m demo_metalake --disable `: disable a metalake - `catalog update -m demo_metalake --name Hive_catalog --disable `: disable a catalog ### Why are the changes needed? Fix: #5826 ### Does this PR introduce _any_ user-facing change? NO ### How was this patch tested? ```bash bin/gcli.sh metalake delete --metalake demo_metalake2 # output: # demo_metalake2 in use, please use disable command disable it first. # demo_metalake2 not deleted. bin/gcli.sh metalake update --metalake demo_metalake --enable # demo_metalake has been enabled. bin/gcli.sh metalake update --metalake demo_metalake --all --enable # demo_metalake has been enabled. and all catalogs in this metalake have been enabled. bin/gcli.sh catalog update --metalake demo_metalake --name Hive_catalog --enable # demo_metalake.Hive_catalog has been enabled. bin/gcli.sh catalog update --metalake demo_metalake --name Hive_catalog --enable --all # demo_metalake.Hive_catalog has been enabled. bin/gcli.sh metalake update --metalake demo_metalake --disable # demo_metalake has been disabled. bin/gcli.sh catalog update --metalake demo_metalake --name Hive_catalog --disable # demo_metalake.Hive_catalog has been disabled. bin/gcli.sh catalog update --metalake demo_metalake --name Hive_catalog --disable --enable # Unable to enable and disable at the same time ``` --------- Co-authored-by: Qiming Teng <ten...@outlook.com> --- .../apache/gravitino/cli/GravitinoCommandLine.java | 24 +++++ .../org/apache/gravitino/cli/GravitinoOptions.java | 6 ++ .../apache/gravitino/cli/TestableCommandLine.java | 23 +++++ .../{DeleteCatalog.java => CatalogDisable.java} | 37 ++----- .../{DeleteCatalog.java => CatalogEnable.java} | 51 +++++---- .../gravitino/cli/commands/DeleteCatalog.java | 3 + .../gravitino/cli/commands/DeleteMetalake.java | 3 + .../{DeleteMetalake.java => MetalakeDisable.java} | 29 ++---- .../{DeleteMetalake.java => MetalakeEnable.java} | 45 ++++---- clients/cli/src/main/resources/catalog_help.txt | 8 +- clients/cli/src/main/resources/metalake_help.txt | 6 ++ .../apache/gravitino/cli/TestCatalogCommands.java | 114 +++++++++++++++++++++ .../java/org/apache/gravitino/cli/TestMain.java | 1 + .../apache/gravitino/cli/TestMetalakeCommands.java | 101 ++++++++++++++++++ docs/cli.md | 36 +++++++ 15 files changed, 391 insertions(+), 96 deletions(-) diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java index bc825443e..7c8539ba1 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoCommandLine.java @@ -213,6 +213,18 @@ public class GravitinoCommandLine extends TestableCommandLine { break; case CommandActions.UPDATE: + if (line.hasOption(GravitinoOptions.ENABLE) && line.hasOption(GravitinoOptions.DISABLE)) { + System.err.println("Unable to enable and disable at the same time"); + Main.exit(-1); + } + if (line.hasOption(GravitinoOptions.ENABLE)) { + boolean enableAllCatalogs = line.hasOption(GravitinoOptions.ALL); + newMetalakeEnable(url, ignore, metalake, enableAllCatalogs).handle(); + } + if (line.hasOption(GravitinoOptions.DISABLE)) { + newMetalakeDisable(url, ignore, metalake).handle(); + } + if (line.hasOption(GravitinoOptions.COMMENT)) { comment = line.getOptionValue(GravitinoOptions.COMMENT); newUpdateMetalakeComment(url, ignore, metalake, comment).handle(); @@ -290,6 +302,18 @@ public class GravitinoCommandLine extends TestableCommandLine { break; case CommandActions.UPDATE: + if (line.hasOption(GravitinoOptions.ENABLE) && line.hasOption(GravitinoOptions.DISABLE)) { + System.err.println("Unable to enable and disable at the same time"); + Main.exit(-1); + } + if (line.hasOption(GravitinoOptions.ENABLE)) { + boolean enableMetalake = line.hasOption(GravitinoOptions.ALL); + newCatalogEnable(url, ignore, metalake, catalog, enableMetalake).handle(); + } + if (line.hasOption(GravitinoOptions.DISABLE)) { + newCatalogDisable(url, ignore, metalake, catalog).handle(); + } + if (line.hasOption(GravitinoOptions.COMMENT)) { String updateComment = line.getOptionValue(GravitinoOptions.COMMENT); newUpdateCatalogComment(url, ignore, metalake, catalog, updateComment).handle(); diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java index a42591026..657566036 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/GravitinoOptions.java @@ -59,6 +59,9 @@ public class GravitinoOptions { public static final String USER = "user"; public static final String VALUE = "value"; public static final String VERSION = "version"; + public static final String ALL = "all"; + public static final String ENABLE = "enable"; + public static final String DISABLE = "disable"; /** * Builds and returns the CLI options for Gravitino. @@ -84,6 +87,8 @@ public class GravitinoOptions { options.addOption(createSimpleOption(PARTITION, "display partition information")); options.addOption(createSimpleOption("o", OWNER, "display entity owner")); options.addOption(createSimpleOption(null, SORTORDER, "display sortorder information")); + options.addOption(createSimpleOption(null, ENABLE, "enable entities")); + options.addOption(createSimpleOption(null, DISABLE, "disable entities")); // Create/update options options.addOption(createArgOption(RENAME, "new entity name")); @@ -102,6 +107,7 @@ public class GravitinoOptions { options.addOption(createArgOption(DEFAULT, "default column value")); options.addOption(createSimpleOption("o", OWNER, "display entity owner")); options.addOption(createArgOption(COLUMNFILE, "CSV file describing columns")); + options.addOption(createSimpleOption(null, ALL, "all operation for --enable")); // Options that support multiple values options.addOption(createArgsOption("p", PROPERTIES, "property name/value pairs")); diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java b/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java index 41909f720..effe0da1f 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/TestableCommandLine.java @@ -26,6 +26,8 @@ import org.apache.gravitino.cli.commands.AddRoleToGroup; import org.apache.gravitino.cli.commands.AddRoleToUser; import org.apache.gravitino.cli.commands.CatalogAudit; import org.apache.gravitino.cli.commands.CatalogDetails; +import org.apache.gravitino.cli.commands.CatalogDisable; +import org.apache.gravitino.cli.commands.CatalogEnable; import org.apache.gravitino.cli.commands.ClientVersion; import org.apache.gravitino.cli.commands.ColumnAudit; import org.apache.gravitino.cli.commands.CreateCatalog; @@ -75,6 +77,8 @@ import org.apache.gravitino.cli.commands.ListTopics; import org.apache.gravitino.cli.commands.ListUsers; import org.apache.gravitino.cli.commands.MetalakeAudit; import org.apache.gravitino.cli.commands.MetalakeDetails; +import org.apache.gravitino.cli.commands.MetalakeDisable; +import org.apache.gravitino.cli.commands.MetalakeEnable; import org.apache.gravitino.cli.commands.OwnerDetails; import org.apache.gravitino.cli.commands.RemoveAllTags; import org.apache.gravitino.cli.commands.RemoveCatalogProperty; @@ -884,4 +888,23 @@ public class TestableCommandLine { String[] privileges) { return new RevokePrivilegesFromRole(url, ignore, metalake, role, entity, privileges); } + + protected MetalakeEnable newMetalakeEnable( + String url, boolean ignore, String metalake, boolean enableAllCatalogs) { + return new MetalakeEnable(url, ignore, metalake, enableAllCatalogs); + } + + protected MetalakeDisable newMetalakeDisable(String url, boolean ignore, String metalake) { + return new MetalakeDisable(url, ignore, metalake); + } + + protected CatalogEnable newCatalogEnable( + String url, boolean ignore, String metalake, String catalog, boolean enableMetalake) { + return new CatalogEnable(url, ignore, metalake, catalog, enableMetalake); + } + + protected CatalogDisable newCatalogDisable( + String url, boolean ignore, String metalake, String catalog) { + return new CatalogDisable(url, ignore, metalake, catalog); + } } diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteCatalog.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/CatalogDisable.java similarity index 68% copy from clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteCatalog.java copy to clients/cli/src/main/java/org/apache/gravitino/cli/commands/CatalogDisable.java index 6c5fbaee9..620a4291e 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteCatalog.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/CatalogDisable.java @@ -16,62 +16,47 @@ * specific language governing permissions and limitations * under the License. */ - package org.apache.gravitino.cli.commands; -import org.apache.gravitino.cli.AreYouSure; import org.apache.gravitino.cli.ErrorMessages; import org.apache.gravitino.client.GravitinoClient; import org.apache.gravitino.exceptions.NoSuchCatalogException; import org.apache.gravitino.exceptions.NoSuchMetalakeException; -public class DeleteCatalog extends Command { +/** Disable catalog. */ +public class CatalogDisable extends Command { - protected final String metalake; - protected final String catalog; - protected final boolean force; + private final String metalake; + private final String catalog; /** - * Delete a catalog. + * Disable catalog * * @param url The URL of the Gravitino server. * @param ignoreVersions If true don't check the client/server versions match. - * @param force Force operation. * @param metalake The name of the metalake. * @param catalog The name of the catalog. */ - public DeleteCatalog( - String url, boolean ignoreVersions, boolean force, String metalake, String catalog) { + public CatalogDisable(String url, boolean ignoreVersions, String metalake, String catalog) { super(url, ignoreVersions); - this.force = force; this.metalake = metalake; this.catalog = catalog; } - /** Delete a catalog. */ + /** Disable catalog. */ @Override public void handle() { - boolean deleted = false; - - if (!AreYouSure.really(force)) { - return; - } - try { GravitinoClient client = buildClient(metalake); - deleted = client.dropCatalog(catalog); - } catch (NoSuchMetalakeException err) { + client.disableCatalog(catalog); + } catch (NoSuchMetalakeException noSuchMetalakeException) { exitWithError(ErrorMessages.UNKNOWN_METALAKE); - } catch (NoSuchCatalogException err) { + } catch (NoSuchCatalogException noSuchCatalogException) { exitWithError(ErrorMessages.UNKNOWN_CATALOG); } catch (Exception exp) { exitWithError(exp.getMessage()); } - if (deleted) { - System.out.println(catalog + " deleted."); - } else { - System.out.println(catalog + " not deleted."); - } + System.out.println(metalake + "." + catalog + " has been disabled."); } } diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteCatalog.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/CatalogEnable.java similarity index 60% copy from clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteCatalog.java copy to clients/cli/src/main/java/org/apache/gravitino/cli/commands/CatalogEnable.java index 6c5fbaee9..8646baee2 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteCatalog.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/CatalogEnable.java @@ -16,62 +16,59 @@ * specific language governing permissions and limitations * under the License. */ - package org.apache.gravitino.cli.commands; -import org.apache.gravitino.cli.AreYouSure; import org.apache.gravitino.cli.ErrorMessages; +import org.apache.gravitino.client.GravitinoAdminClient; import org.apache.gravitino.client.GravitinoClient; +import org.apache.gravitino.exceptions.MetalakeNotInUseException; import org.apache.gravitino.exceptions.NoSuchCatalogException; import org.apache.gravitino.exceptions.NoSuchMetalakeException; -public class DeleteCatalog extends Command { - - protected final String metalake; - protected final String catalog; - protected final boolean force; +/** Enable catalog. */ +public class CatalogEnable extends Command { + private final String metalake; + private final String catalog; + private final boolean enableMetalake; /** - * Delete a catalog. + * Enable catalog * * @param url The URL of the Gravitino server. * @param ignoreVersions If true don't check the client/server versions match. - * @param force Force operation. * @param metalake The name of the metalake. * @param catalog The name of the catalog. + * @param enableMetalake Whether to enable it's metalake */ - public DeleteCatalog( - String url, boolean ignoreVersions, boolean force, String metalake, String catalog) { + public CatalogEnable( + String url, boolean ignoreVersions, String metalake, String catalog, boolean enableMetalake) { super(url, ignoreVersions); - this.force = force; this.metalake = metalake; this.catalog = catalog; + this.enableMetalake = enableMetalake; } - /** Delete a catalog. */ + /** Enable catalog. */ @Override public void handle() { - boolean deleted = false; - - if (!AreYouSure.really(force)) { - return; - } - try { + if (enableMetalake) { + GravitinoAdminClient adminClient = buildAdminClient(); + adminClient.enableMetalake(metalake); + } GravitinoClient client = buildClient(metalake); - deleted = client.dropCatalog(catalog); - } catch (NoSuchMetalakeException err) { + client.enableCatalog(catalog); + } catch (NoSuchMetalakeException noSuchMetalakeException) { exitWithError(ErrorMessages.UNKNOWN_METALAKE); - } catch (NoSuchCatalogException err) { + } catch (NoSuchCatalogException noSuchCatalogException) { exitWithError(ErrorMessages.UNKNOWN_CATALOG); + } catch (MetalakeNotInUseException notInUseException) { + exitWithError( + metalake + " not in use. please use --recursive option, or enable metalake first"); } catch (Exception exp) { exitWithError(exp.getMessage()); } - if (deleted) { - System.out.println(catalog + " deleted."); - } else { - System.out.println(catalog + " not deleted."); - } + System.out.println(metalake + "." + catalog + " has been enabled."); } } diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteCatalog.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteCatalog.java index 6c5fbaee9..6aa8e5ad9 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteCatalog.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteCatalog.java @@ -22,6 +22,7 @@ package org.apache.gravitino.cli.commands; import org.apache.gravitino.cli.AreYouSure; import org.apache.gravitino.cli.ErrorMessages; import org.apache.gravitino.client.GravitinoClient; +import org.apache.gravitino.exceptions.CatalogInUseException; import org.apache.gravitino.exceptions.NoSuchCatalogException; import org.apache.gravitino.exceptions.NoSuchMetalakeException; @@ -64,6 +65,8 @@ public class DeleteCatalog extends Command { exitWithError(ErrorMessages.UNKNOWN_METALAKE); } catch (NoSuchCatalogException err) { exitWithError(ErrorMessages.UNKNOWN_CATALOG); + } catch (CatalogInUseException catalogInUseException) { + System.err.println(catalog + " in use, please disable it first."); } catch (Exception exp) { exitWithError(exp.getMessage()); } diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteMetalake.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteMetalake.java index 386dde921..e88ae4148 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteMetalake.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteMetalake.java @@ -22,6 +22,7 @@ package org.apache.gravitino.cli.commands; import org.apache.gravitino.cli.AreYouSure; import org.apache.gravitino.cli.ErrorMessages; import org.apache.gravitino.client.GravitinoAdminClient; +import org.apache.gravitino.exceptions.MetalakeInUseException; import org.apache.gravitino.exceptions.NoSuchMetalakeException; public class DeleteMetalake extends Command { @@ -56,6 +57,8 @@ public class DeleteMetalake extends Command { deleted = client.dropMetalake(metalake); } catch (NoSuchMetalakeException err) { exitWithError(ErrorMessages.UNKNOWN_METALAKE); + } catch (MetalakeInUseException inUseException) { + System.err.println(metalake + " in use, please disable it first."); } catch (Exception exp) { exitWithError(exp.getMessage()); } diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteMetalake.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/MetalakeDisable.java similarity index 70% copy from clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteMetalake.java copy to clients/cli/src/main/java/org/apache/gravitino/cli/commands/MetalakeDisable.java index 386dde921..02e33a45d 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteMetalake.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/MetalakeDisable.java @@ -19,51 +19,38 @@ package org.apache.gravitino.cli.commands; -import org.apache.gravitino.cli.AreYouSure; import org.apache.gravitino.cli.ErrorMessages; import org.apache.gravitino.client.GravitinoAdminClient; import org.apache.gravitino.exceptions.NoSuchMetalakeException; -public class DeleteMetalake extends Command { - protected final String metalake; - protected final boolean force; +/** Disable metalake. */ +public class MetalakeDisable extends Command { + private String metalake; /** - * Delete a metalake. + * Disable metalake * * @param url The URL of the Gravitino server. * @param ignoreVersions If true don't check the client/server versions match. - * @param force Force operation. * @param metalake The name of the metalake. */ - public DeleteMetalake(String url, boolean ignoreVersions, boolean force, String metalake) { + public MetalakeDisable(String url, boolean ignoreVersions, String metalake) { super(url, ignoreVersions); - this.force = force; this.metalake = metalake; } - /** Delete a metalake. */ + /** Disable metalake. */ @Override public void handle() { - boolean deleted = false; - - if (!AreYouSure.really(force)) { - return; - } - try { GravitinoAdminClient client = buildAdminClient(); - deleted = client.dropMetalake(metalake); + client.disableMetalake(metalake); } catch (NoSuchMetalakeException err) { exitWithError(ErrorMessages.UNKNOWN_METALAKE); } catch (Exception exp) { exitWithError(exp.getMessage()); } - if (deleted) { - System.out.println(metalake + " deleted."); - } else { - System.out.println(metalake + " not deleted."); - } + System.out.println(metalake + " has been disabled."); } } diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteMetalake.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/MetalakeEnable.java similarity index 61% copy from clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteMetalake.java copy to clients/cli/src/main/java/org/apache/gravitino/cli/commands/MetalakeEnable.java index 386dde921..34ba23a61 100644 --- a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/DeleteMetalake.java +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/MetalakeEnable.java @@ -19,51 +19,54 @@ package org.apache.gravitino.cli.commands; -import org.apache.gravitino.cli.AreYouSure; +import java.util.Arrays; import org.apache.gravitino.cli.ErrorMessages; import org.apache.gravitino.client.GravitinoAdminClient; +import org.apache.gravitino.client.GravitinoMetalake; import org.apache.gravitino.exceptions.NoSuchMetalakeException; -public class DeleteMetalake extends Command { - protected final String metalake; - protected final boolean force; +/** Enable metalake. */ +public class MetalakeEnable extends Command { + + private final String metalake; + private Boolean enableAllCatalogs; /** - * Delete a metalake. + * Enable a metalake * * @param url The URL of the Gravitino server. * @param ignoreVersions If true don't check the client/server versions match. - * @param force Force operation. * @param metalake The name of the metalake. + * @param enableAllCatalogs Whether to enable all catalogs. */ - public DeleteMetalake(String url, boolean ignoreVersions, boolean force, String metalake) { + public MetalakeEnable( + String url, boolean ignoreVersions, String metalake, boolean enableAllCatalogs) { super(url, ignoreVersions); - this.force = force; this.metalake = metalake; + this.enableAllCatalogs = enableAllCatalogs; } - /** Delete a metalake. */ + /** Enable metalake. */ @Override public void handle() { - boolean deleted = false; - - if (!AreYouSure.really(force)) { - return; - } - + StringBuilder msgBuilder = new StringBuilder(metalake); try { GravitinoAdminClient client = buildAdminClient(); - deleted = client.dropMetalake(metalake); + client.enableMetalake(metalake); + msgBuilder.append(" has been enabled."); + + if (enableAllCatalogs) { + GravitinoMetalake metalakeObject = client.loadMetalake(metalake); + String[] catalogs = metalakeObject.listCatalogs(); + Arrays.stream(catalogs).forEach(metalakeObject::enableCatalog); + msgBuilder.append(" and all catalogs in this metalake have been enabled."); + } } catch (NoSuchMetalakeException err) { exitWithError(ErrorMessages.UNKNOWN_METALAKE); } catch (Exception exp) { exitWithError(exp.getMessage()); } - if (deleted) { - System.out.println(metalake + " deleted."); - } else { - System.out.println(metalake + " not deleted."); - } + System.out.println(msgBuilder); } } diff --git a/clients/cli/src/main/resources/catalog_help.txt b/clients/cli/src/main/resources/catalog_help.txt index 27ba7eeac..c29e9dcad 100644 --- a/clients/cli/src/main/resources/catalog_help.txt +++ b/clients/cli/src/main/resources/catalog_help.txt @@ -47,4 +47,10 @@ Set a catalog's property gcli catalog set --name catalog_mysql --property test --value value Remove a catalog's property -gcli catalog remove --name catalog_mysql --property test \ No newline at end of file +gcli catalog remove --name catalog_mysql --property test + +Enable a catalog +gcli catalog update -m metalake_demo --name catalog --enable + +Disable a catalog +gcli catalog update -m metalake_demo --name catalog --disable \ No newline at end of file diff --git a/clients/cli/src/main/resources/metalake_help.txt b/clients/cli/src/main/resources/metalake_help.txt index c80d244f5..f700d3a07 100644 --- a/clients/cli/src/main/resources/metalake_help.txt +++ b/clients/cli/src/main/resources/metalake_help.txt @@ -38,3 +38,9 @@ gcli metalake set --property test --value value Remove a metalake's property gcli metalake remove --property test + +Enable a metalake +gcli metalake update -m metalake_demo --enable + +Disable a metalke +gcli metalake update -m metalake_demo --disable \ No newline at end of file diff --git a/clients/cli/src/test/java/org/apache/gravitino/cli/TestCatalogCommands.java b/clients/cli/src/test/java/org/apache/gravitino/cli/TestCatalogCommands.java index eb8bc46d3..d751d6717 100644 --- a/clients/cli/src/test/java/org/apache/gravitino/cli/TestCatalogCommands.java +++ b/clients/cli/src/test/java/org/apache/gravitino/cli/TestCatalogCommands.java @@ -19,17 +19,24 @@ package org.apache.gravitino.cli; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.util.HashMap; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; import org.apache.gravitino.cli.commands.CatalogAudit; import org.apache.gravitino.cli.commands.CatalogDetails; +import org.apache.gravitino.cli.commands.CatalogDisable; +import org.apache.gravitino.cli.commands.CatalogEnable; import org.apache.gravitino.cli.commands.CreateCatalog; import org.apache.gravitino.cli.commands.DeleteCatalog; import org.apache.gravitino.cli.commands.ListCatalogProperties; @@ -38,6 +45,7 @@ import org.apache.gravitino.cli.commands.RemoveCatalogProperty; import org.apache.gravitino.cli.commands.SetCatalogProperty; import org.apache.gravitino.cli.commands.UpdateCatalogComment; import org.apache.gravitino.cli.commands.UpdateCatalogName; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -45,10 +53,28 @@ class TestCatalogCommands { private CommandLine mockCommandLine; private Options mockOptions; + private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + private final ByteArrayOutputStream errContent = new ByteArrayOutputStream(); + private final PrintStream originalOut = System.out; + private final PrintStream originalErr = System.err; + @BeforeEach void setUp() { mockCommandLine = mock(CommandLine.class); mockOptions = mock(Options.class); + System.setOut(new PrintStream(outContent)); + System.setErr(new PrintStream(errContent)); + } + + @AfterEach + void restoreExitFlg() { + Main.useExit = true; + } + + @AfterEach + public void restoreStreams() { + System.setOut(originalOut); + System.setErr(originalErr); } @Test @@ -291,4 +317,92 @@ class TestCatalogCommands { commandLine.handleCommandLine(); verify(mockUpdateName).handle(); } + + @Test + void testEnableCatalogCommand() { + CatalogEnable mockEnable = mock(CatalogEnable.class); + when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true); + when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo"); + when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true); + when(mockCommandLine.getOptionValue(GravitinoOptions.NAME)).thenReturn("catalog"); + when(mockCommandLine.hasOption(GravitinoOptions.ENABLE)).thenReturn(true); + + GravitinoCommandLine commandLine = + spy( + new GravitinoCommandLine( + mockCommandLine, mockOptions, CommandEntities.CATALOG, CommandActions.UPDATE)); + doReturn(mockEnable) + .when(commandLine) + .newCatalogEnable( + GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo", "catalog", false); + commandLine.handleCommandLine(); + verify(mockEnable).handle(); + } + + @Test + void testEnableCatalogCommandWithRecursive() { + CatalogEnable mockEnable = mock(CatalogEnable.class); + when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true); + when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo"); + when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true); + when(mockCommandLine.getOptionValue(GravitinoOptions.NAME)).thenReturn("catalog"); + when(mockCommandLine.hasOption(GravitinoOptions.ALL)).thenReturn(true); + when(mockCommandLine.hasOption(GravitinoOptions.ENABLE)).thenReturn(true); + + GravitinoCommandLine commandLine = + spy( + new GravitinoCommandLine( + mockCommandLine, mockOptions, CommandEntities.CATALOG, CommandActions.UPDATE)); + doReturn(mockEnable) + .when(commandLine) + .newCatalogEnable( + GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo", "catalog", true); + commandLine.handleCommandLine(); + verify(mockEnable).handle(); + } + + @Test + void testDisableCatalogCommand() { + CatalogDisable mockDisable = mock(CatalogDisable.class); + when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true); + when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo"); + when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true); + when(mockCommandLine.getOptionValue(GravitinoOptions.NAME)).thenReturn("catalog"); + when(mockCommandLine.hasOption(GravitinoOptions.DISABLE)).thenReturn(true); + + GravitinoCommandLine commandLine = + spy( + new GravitinoCommandLine( + mockCommandLine, mockOptions, CommandEntities.CATALOG, CommandActions.UPDATE)); + doReturn(mockDisable) + .when(commandLine) + .newCatalogDisable(GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo", "catalog"); + commandLine.handleCommandLine(); + verify(mockDisable).handle(); + } + + @Test + @SuppressWarnings("DefaultCharset") + void testCatalogWithDisableAndEnableOptions() { + Main.useExit = false; + when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true); + when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo"); + when(mockCommandLine.hasOption(GravitinoOptions.NAME)).thenReturn(true); + when(mockCommandLine.getOptionValue(GravitinoOptions.NAME)).thenReturn("catalog"); + when(mockCommandLine.hasOption(GravitinoOptions.DISABLE)).thenReturn(true); + when(mockCommandLine.hasOption(GravitinoOptions.ENABLE)).thenReturn(true); + + GravitinoCommandLine commandLine = + spy( + new GravitinoCommandLine( + mockCommandLine, mockOptions, CommandEntities.CATALOG, CommandActions.UPDATE)); + + assertThrows(RuntimeException.class, commandLine::handleCommandLine); + verify(commandLine, never()) + .newCatalogEnable( + GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo", "catalog", false); + verify(commandLine, never()) + .newCatalogDisable(GravitinoCommandLine.DEFAULT_URL, false, "melake_demo", "catalog"); + assertTrue(errContent.toString().contains("Unable to enable and disable at the same time")); + } } diff --git a/clients/cli/src/test/java/org/apache/gravitino/cli/TestMain.java b/clients/cli/src/test/java/org/apache/gravitino/cli/TestMain.java index 93de0a6bc..377e569aa 100644 --- a/clients/cli/src/test/java/org/apache/gravitino/cli/TestMain.java +++ b/clients/cli/src/test/java/org/apache/gravitino/cli/TestMain.java @@ -150,6 +150,7 @@ public class TestMain { assertEquals(CommandEntities.CATALOG, entity); } + @Test public void metalakeWithHelpOption() throws ParseException { Options options = new GravitinoOptions().options(); CommandLineParser parser = new DefaultParser(); diff --git a/clients/cli/src/test/java/org/apache/gravitino/cli/TestMetalakeCommands.java b/clients/cli/src/test/java/org/apache/gravitino/cli/TestMetalakeCommands.java index b7468b635..01eebb6da 100644 --- a/clients/cli/src/test/java/org/apache/gravitino/cli/TestMetalakeCommands.java +++ b/clients/cli/src/test/java/org/apache/gravitino/cli/TestMetalakeCommands.java @@ -19,12 +19,16 @@ package org.apache.gravitino.cli; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; import org.apache.gravitino.cli.commands.CreateMetalake; @@ -33,21 +37,42 @@ import org.apache.gravitino.cli.commands.ListMetalakeProperties; import org.apache.gravitino.cli.commands.ListMetalakes; import org.apache.gravitino.cli.commands.MetalakeAudit; import org.apache.gravitino.cli.commands.MetalakeDetails; +import org.apache.gravitino.cli.commands.MetalakeDisable; +import org.apache.gravitino.cli.commands.MetalakeEnable; import org.apache.gravitino.cli.commands.RemoveMetalakeProperty; import org.apache.gravitino.cli.commands.SetMetalakeProperty; import org.apache.gravitino.cli.commands.UpdateMetalakeComment; import org.apache.gravitino.cli.commands.UpdateMetalakeName; +import org.junit.Assert; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class TestMetalakeCommands { private CommandLine mockCommandLine; private Options mockOptions; + private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + private final ByteArrayOutputStream errContent = new ByteArrayOutputStream(); + private final PrintStream originalOut = System.out; + private final PrintStream originalErr = System.err; @BeforeEach void setUp() { mockCommandLine = mock(CommandLine.class); mockOptions = mock(Options.class); + System.setOut(new PrintStream(outContent)); + System.setErr(new PrintStream(errContent)); + } + + @AfterEach + void restoreExitFlg() { + Main.useExit = true; + } + + @AfterEach + public void restoreStreams() { + System.setOut(originalOut); + System.setErr(originalErr); } @Test @@ -280,4 +305,80 @@ class TestMetalakeCommands { commandLine.handleCommandLine(); verify(mockUpdateName).handle(); } + + @Test + void testEnableMetalakeCommand() { + MetalakeEnable mockEnable = mock(MetalakeEnable.class); + when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true); + when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo"); + when(mockCommandLine.hasOption(GravitinoOptions.ENABLE)).thenReturn(true); + GravitinoCommandLine commandLine = + spy( + new GravitinoCommandLine( + mockCommandLine, mockOptions, CommandEntities.METALAKE, CommandActions.UPDATE)); + doReturn(mockEnable) + .when(commandLine) + .newMetalakeEnable(GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo", false); + commandLine.handleCommandLine(); + verify(mockEnable).handle(); + } + + @Test + void testEnableMetalakeCommandWithRecursive() { + MetalakeEnable mockEnable = mock(MetalakeEnable.class); + when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true); + when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo"); + when(mockCommandLine.hasOption(GravitinoOptions.ALL)).thenReturn(true); + when(mockCommandLine.hasOption(GravitinoOptions.ENABLE)).thenReturn(true); + GravitinoCommandLine commandLine = + spy( + new GravitinoCommandLine( + mockCommandLine, mockOptions, CommandEntities.METALAKE, CommandActions.UPDATE)); + doReturn(mockEnable) + .when(commandLine) + .newMetalakeEnable(GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo", true); + commandLine.handleCommandLine(); + verify(mockEnable).handle(); + } + + @Test + void testDisableMetalakeCommand() { + MetalakeDisable mockDisable = mock(MetalakeDisable.class); + when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true); + when(mockCommandLine.getOptionValue(GravitinoOptions.METALAKE)).thenReturn("metalake_demo"); + when(mockCommandLine.hasOption(GravitinoOptions.DISABLE)).thenReturn(true); + + GravitinoCommandLine commandLine = + spy( + new GravitinoCommandLine( + mockCommandLine, mockOptions, CommandEntities.METALAKE, CommandActions.UPDATE)); + doReturn(mockDisable) + .when(commandLine) + .newMetalakeDisable(GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo"); + + commandLine.handleCommandLine(); + verify(mockDisable).handle(); + } + + @Test + @SuppressWarnings("DefaultCharset") + void testMetalakeWithDisableAndEnableOptions() { + Main.useExit = false; + when(mockCommandLine.hasOption(GravitinoOptions.METALAKE)).thenReturn(true); + when(mockCommandLine.getOptionValue(CommandEntities.METALAKE)).thenReturn("metalake_demo"); + when(mockCommandLine.hasOption(GravitinoOptions.ENABLE)).thenReturn(true); + when(mockCommandLine.hasOption(GravitinoOptions.DISABLE)).thenReturn(true); + + GravitinoCommandLine commandLine = + spy( + new GravitinoCommandLine( + mockCommandLine, mockOptions, CommandEntities.METALAKE, CommandActions.UPDATE)); + + Assert.assertThrows(RuntimeException.class, commandLine::handleCommandLine); + verify(commandLine, never()) + .newMetalakeEnable(GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo", false); + verify(commandLine, never()) + .newMetalakeEnable(GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo", false); + assertTrue(errContent.toString().contains("Unable to enable and disable at the same time")); + } } diff --git a/docs/cli.md b/docs/cli.md index e6e2f5aa6..64d720f2e 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -276,6 +276,24 @@ gcli metalake set --property test --value value gcli metalake remove --property test ``` +#### Enable a metalake + +```bash +gcli metalake update -m metalake_demo --enable +``` + +#### Enable a metalake and all catalogs + +```bash +gcli metalake update -m metalake_demo --enable --all +``` + +#### Disable a metalake + +```bash +gcli metalake update -m metalake_demo --disable +``` + ### Catalog commands #### Show all catalogs in a metalake @@ -390,6 +408,24 @@ gcli catalog set --name catalog_mysql --property test --value value gcli catalog remove --name catalog_mysql --property test ``` +#### Enable a catalog + +```bash +gcli catalog update -m metalake_demo --name catalog --enable +``` + +#### Enable a catalog and it's metalake + +```bash +gcli catalog update -m metalake_demo --name catalog --enable --all +``` + +#### Disable a catalog + +```bash +gcli catalog update -m metalake_demo --name catalog --disable +``` + ### Schema commands #### Show all schemas in a catalog