This is an automated email from the ASF dual-hosted git repository. shaofengshi 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 b0e4686b5 [#5383] Add table property commands to Gravitino CLI (#5390) b0e4686b5 is described below commit b0e4686b50e13dc44dc1516225ee43068281fc2f Author: Justin Mclean <jus...@classsoftware.com> AuthorDate: Mon Dec 2 13:16:43 2024 +1100 [#5383] Add table property commands to Gravitino CLI (#5390) ### What changes were proposed in this pull request? Added table property commands to Gravitino CLI. ### Why are the changes needed? The expand the CLI support. Fix: #5383 ### Does this PR introduce _any_ user-facing change? No, but it adds more commands. ### How was this patch tested? Tested locally with Hive, Postgres and MySQL databases. Note that database support varies. --- .../apache/gravitino/cli/GravitinoCommandLine.java | 9 ++ .../apache/gravitino/cli/TestableCommandLine.java | 31 +++++++ .../cli/commands/ListTableProperties.java | 92 ++++++++++++++++++++ .../cli/commands/RemoveTableProperty.java | 94 +++++++++++++++++++++ .../gravitino/cli/commands/SetTableProperty.java | 98 ++++++++++++++++++++++ .../apache/gravitino/cli/TestTableCommands.java | 82 ++++++++++++++++++ docs/cli.md | 36 ++++++-- 7 files changed, 434 insertions(+), 8 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 123f45fc1..ca149672a 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 @@ -315,6 +315,15 @@ public class GravitinoCommandLine extends TestableCommandLine { } else if (CommandActions.DELETE.equals(command)) { boolean force = line.hasOption(GravitinoOptions.FORCE); newDeleteTable(url, ignore, force, metalake, catalog, schema, table).handle(); + } else if (CommandActions.SET.equals(command)) { + String property = line.getOptionValue(GravitinoOptions.PROPERTY); + String value = line.getOptionValue(GravitinoOptions.VALUE); + newSetTableProperty(url, ignore, metalake, catalog, schema, table, property, value).handle(); + } else if (CommandActions.REMOVE.equals(command)) { + String property = line.getOptionValue(GravitinoOptions.PROPERTY); + newRemoveTableProperty(url, ignore, metalake, catalog, schema, table, property).handle(); + } else if (CommandActions.PROPERTIES.equals(command)) { + newListTableProperties(url, ignore, metalake, catalog, schema, table).handle(); } } 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 adcfd7eff..248f57cd6 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 @@ -61,6 +61,7 @@ import org.apache.gravitino.cli.commands.ListMetalakes; import org.apache.gravitino.cli.commands.ListRoles; import org.apache.gravitino.cli.commands.ListSchema; import org.apache.gravitino.cli.commands.ListSchemaProperties; +import org.apache.gravitino.cli.commands.ListTableProperties; import org.apache.gravitino.cli.commands.ListTables; import org.apache.gravitino.cli.commands.ListTagProperties; import org.apache.gravitino.cli.commands.ListTopicProperties; @@ -75,6 +76,7 @@ import org.apache.gravitino.cli.commands.RemoveMetalakeProperty; import org.apache.gravitino.cli.commands.RemoveRoleFromGroup; import org.apache.gravitino.cli.commands.RemoveRoleFromUser; import org.apache.gravitino.cli.commands.RemoveSchemaProperty; +import org.apache.gravitino.cli.commands.RemoveTableProperty; import org.apache.gravitino.cli.commands.RemoveTagProperty; import org.apache.gravitino.cli.commands.RemoveTopicProperty; import org.apache.gravitino.cli.commands.RoleDetails; @@ -86,6 +88,7 @@ import org.apache.gravitino.cli.commands.SetFilesetProperty; import org.apache.gravitino.cli.commands.SetMetalakeProperty; import org.apache.gravitino.cli.commands.SetOwner; import org.apache.gravitino.cli.commands.SetSchemaProperty; +import org.apache.gravitino.cli.commands.SetTableProperty; import org.apache.gravitino.cli.commands.SetTagProperty; import org.apache.gravitino.cli.commands.SetTopicProperty; import org.apache.gravitino.cli.commands.TableAudit; @@ -310,6 +313,34 @@ public class TestableCommandLine { return new TableDistribution(url, ignore, metalake, catalog, schema, table); } + protected SetTableProperty newSetTableProperty( + String url, + boolean ignore, + String metalake, + String catalog, + String schema, + String table, + String property, + String value) { + return new SetTableProperty(url, ignore, metalake, catalog, schema, table, property, value); + } + + protected RemoveTableProperty newRemoveTableProperty( + String url, + boolean ignore, + String metalake, + String catalog, + String schema, + String table, + String property) { + return new RemoveTableProperty(url, ignore, metalake, catalog, schema, table, property); + } + + protected ListTableProperties newListTableProperties( + String url, boolean ignore, String metalake, String catalog, String schema, String table) { + return new ListTableProperties(url, ignore, metalake, catalog, schema, table); + } + protected UserDetails newUserDetails(String url, boolean ignore, String metalake, String user) { return new UserDetails(url, ignore, metalake, user); } diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListTableProperties.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListTableProperties.java new file mode 100644 index 000000000..a6d7d6a0b --- /dev/null +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/ListTableProperties.java @@ -0,0 +1,92 @@ +/* + * 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.gravitino.cli.commands; + +import java.util.Map; +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.cli.ErrorMessages; +import org.apache.gravitino.client.GravitinoClient; +import org.apache.gravitino.exceptions.NoSuchCatalogException; +import org.apache.gravitino.exceptions.NoSuchMetalakeException; +import org.apache.gravitino.exceptions.NoSuchSchemaException; +import org.apache.gravitino.exceptions.NoSuchTableException; +import org.apache.gravitino.rel.Table; + +/** List the properties of a table. */ +public class ListTableProperties extends ListProperties { + + protected final String metalake; + protected final String catalog; + protected final String schema; + protected final String table; + + /** + * List the properties of a table. + * + * @param url The URL of the Gravitino server. + * @param ignoreVersions If true don't check the client/server versions match. + * @param metalake The name of the metalake. + * @param catalog The name of the catalog. + * @param schema The name of the schema. + * @param table The name of the table. + */ + public ListTableProperties( + String url, + boolean ignoreVersions, + String metalake, + String catalog, + String schema, + String table) { + super(url, ignoreVersions); + this.metalake = metalake; + this.catalog = catalog; + this.schema = schema; + this.table = table; + } + + /** List the properties of a table. */ + @Override + public void handle() { + Table gTable = null; + try { + NameIdentifier name = NameIdentifier.of(schema, table); + GravitinoClient client = buildClient(metalake); + gTable = client.loadCatalog(catalog).asTableCatalog().loadTable(name); + } catch (NoSuchMetalakeException err) { + System.err.println(ErrorMessages.UNKNOWN_METALAKE); + return; + } catch (NoSuchCatalogException err) { + System.err.println(ErrorMessages.UNKNOWN_CATALOG); + return; + } catch (NoSuchSchemaException err) { + System.err.println(ErrorMessages.UNKNOWN_SCHEMA); + return; + } catch (NoSuchTableException err) { + System.err.println(ErrorMessages.UNKNOWN_TABLE); + return; + } catch (Exception exp) { + System.err.println(exp.getMessage()); + return; + } + + Map<String, String> properties = gTable.properties(); + printProperties(properties); + } +} diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/RemoveTableProperty.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/RemoveTableProperty.java new file mode 100644 index 000000000..a80580885 --- /dev/null +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/RemoveTableProperty.java @@ -0,0 +1,94 @@ +/* + * 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.gravitino.cli.commands; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.cli.ErrorMessages; +import org.apache.gravitino.client.GravitinoClient; +import org.apache.gravitino.exceptions.NoSuchCatalogException; +import org.apache.gravitino.exceptions.NoSuchMetalakeException; +import org.apache.gravitino.exceptions.NoSuchSchemaException; +import org.apache.gravitino.exceptions.NoSuchTableException; +import org.apache.gravitino.rel.TableChange; + +/** Remove a property of a table. */ +public class RemoveTableProperty extends Command { + + protected final String metalake; + protected final String catalog; + protected final String schema; + protected final String table; + protected final String property; + + /** + * Remove a property of a table. + * + * @param url The URL of the Gravitino server. + * @param ignoreVersions If true don't check the client/server versions match. + * @param metalake The name of the metalake. + * @param catalog The name of the catalog. + * @param schema The name of the schema. + * @param table The name of the table. + * @param property The name of the property. + */ + public RemoveTableProperty( + String url, + boolean ignoreVersions, + String metalake, + String catalog, + String schema, + String table, + String property) { + super(url, ignoreVersions); + this.metalake = metalake; + this.catalog = catalog; + this.schema = schema; + this.table = table; + this.property = property; + } + + /** Remove a property of a table. */ + @Override + public void handle() { + try { + NameIdentifier name = NameIdentifier.of(schema, table); + GravitinoClient client = buildClient(metalake); + TableChange change = TableChange.removeProperty(property); + client.loadCatalog(catalog).asTableCatalog().alterTable(name, change); + } catch (NoSuchMetalakeException err) { + System.err.println(ErrorMessages.UNKNOWN_METALAKE); + return; + } catch (NoSuchCatalogException err) { + System.err.println(ErrorMessages.UNKNOWN_CATALOG); + return; + } catch (NoSuchSchemaException err) { + System.err.println(ErrorMessages.UNKNOWN_SCHEMA); + return; + } catch (NoSuchTableException err) { + System.err.println(ErrorMessages.UNKNOWN_TABLE); + return; + } catch (Exception exp) { + System.err.println(exp.getMessage()); + return; + } + + System.out.println(property + " property removed."); + } +} diff --git a/clients/cli/src/main/java/org/apache/gravitino/cli/commands/SetTableProperty.java b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/SetTableProperty.java new file mode 100644 index 000000000..03fd787da --- /dev/null +++ b/clients/cli/src/main/java/org/apache/gravitino/cli/commands/SetTableProperty.java @@ -0,0 +1,98 @@ +/* + * 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.gravitino.cli.commands; + +import org.apache.gravitino.NameIdentifier; +import org.apache.gravitino.cli.ErrorMessages; +import org.apache.gravitino.client.GravitinoClient; +import org.apache.gravitino.exceptions.NoSuchCatalogException; +import org.apache.gravitino.exceptions.NoSuchMetalakeException; +import org.apache.gravitino.exceptions.NoSuchSchemaException; +import org.apache.gravitino.exceptions.NoSuchTableException; +import org.apache.gravitino.rel.TableChange; + +/** Set a property of a table. */ +public class SetTableProperty extends Command { + + protected final String metalake; + protected final String catalog; + protected final String schema; + protected final String table; + protected final String property; + protected final String value; + + /** + * Set a property of a table. + * + * @param url The URL of the Gravitino server. + * @param ignoreVersions If true don't check the client/server versions match. + * @param metalake The name of the metalake. + * @param catalog The name of the catalog. + * @param schema The name of the schema. + * @param table The name of the table. + * @param property The name of the property. + * @param value The value of the property. + */ + public SetTableProperty( + String url, + boolean ignoreVersions, + String metalake, + String catalog, + String schema, + String table, + String property, + String value) { + super(url, ignoreVersions); + this.metalake = metalake; + this.catalog = catalog; + this.schema = schema; + this.table = table; + this.property = property; + this.value = value; + } + + /** Set a property of a table. */ + @Override + public void handle() { + try { + NameIdentifier name = NameIdentifier.of(schema, table); + GravitinoClient client = buildClient(metalake); + TableChange change = TableChange.setProperty(property, value); + client.loadCatalog(catalog).asTableCatalog().alterTable(name, change); + } catch (NoSuchMetalakeException err) { + System.err.println(ErrorMessages.UNKNOWN_METALAKE); + return; + } catch (NoSuchCatalogException err) { + System.err.println(ErrorMessages.UNKNOWN_CATALOG); + return; + } catch (NoSuchSchemaException err) { + System.err.println(ErrorMessages.UNKNOWN_SCHEMA); + return; + } catch (NoSuchTableException err) { + System.err.println(ErrorMessages.UNKNOWN_TABLE); + return; + } catch (Exception exp) { + System.err.println(exp.getMessage()); + return; + } + + System.out.println(table + " property set."); + } +} diff --git a/clients/cli/src/test/java/org/apache/gravitino/cli/TestTableCommands.java b/clients/cli/src/test/java/org/apache/gravitino/cli/TestTableCommands.java index e2ccca7ed..59b6511be 100644 --- a/clients/cli/src/test/java/org/apache/gravitino/cli/TestTableCommands.java +++ b/clients/cli/src/test/java/org/apache/gravitino/cli/TestTableCommands.java @@ -29,7 +29,10 @@ import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; import org.apache.gravitino.cli.commands.DeleteTable; import org.apache.gravitino.cli.commands.ListIndexes; +import org.apache.gravitino.cli.commands.ListTableProperties; import org.apache.gravitino.cli.commands.ListTables; +import org.apache.gravitino.cli.commands.RemoveTableProperty; +import org.apache.gravitino.cli.commands.SetTableProperty; import org.apache.gravitino.cli.commands.TableAudit; import org.apache.gravitino.cli.commands.TableDetails; import org.apache.gravitino.cli.commands.TableDistribution; @@ -217,4 +220,83 @@ class TestTableCommands { commandLine.handleCommandLine(); verify(mockDelete).handle(); } + + @Test + void testListTablePropertiesCommand() { + ListTableProperties mockListProperties = mock(ListTableProperties.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.schema.users"); + GravitinoCommandLine commandLine = + spy( + new GravitinoCommandLine( + mockCommandLine, mockOptions, CommandEntities.TABLE, CommandActions.PROPERTIES)); + doReturn(mockListProperties) + .when(commandLine) + .newListTableProperties( + GravitinoCommandLine.DEFAULT_URL, false, "metalake_demo", "catalog", "schema", "users"); + commandLine.handleCommandLine(); + verify(mockListProperties).handle(); + } + + @Test + void testSetFilesetPropertyCommand() { + SetTableProperty mockSetProperties = mock(SetTableProperty.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.schema.user"); + when(mockCommandLine.hasOption(GravitinoOptions.PROPERTY)).thenReturn(true); + when(mockCommandLine.getOptionValue(GravitinoOptions.PROPERTY)).thenReturn("property"); + when(mockCommandLine.hasOption(GravitinoOptions.VALUE)).thenReturn(true); + when(mockCommandLine.getOptionValue(GravitinoOptions.VALUE)).thenReturn("value"); + GravitinoCommandLine commandLine = + spy( + new GravitinoCommandLine( + mockCommandLine, mockOptions, CommandEntities.TABLE, CommandActions.SET)); + doReturn(mockSetProperties) + .when(commandLine) + .newSetTableProperty( + GravitinoCommandLine.DEFAULT_URL, + false, + "metalake_demo", + "catalog", + "schema", + "user", + "property", + "value"); + commandLine.handleCommandLine(); + verify(mockSetProperties).handle(); + } + + @Test + void testRemoveTablePropertyCommand() { + RemoveTableProperty mockSetProperties = mock(RemoveTableProperty.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.schema.users"); + when(mockCommandLine.hasOption(GravitinoOptions.PROPERTY)).thenReturn(true); + when(mockCommandLine.getOptionValue(GravitinoOptions.PROPERTY)).thenReturn("property"); + GravitinoCommandLine commandLine = + spy( + new GravitinoCommandLine( + mockCommandLine, mockOptions, CommandEntities.TABLE, CommandActions.REMOVE)); + doReturn(mockSetProperties) + .when(commandLine) + .newRemoveTableProperty( + GravitinoCommandLine.DEFAULT_URL, + false, + "metalake_demo", + "catalog", + "schema", + "users", + "property"); + commandLine.handleCommandLine(); + verify(mockSetProperties).handle(); + } } diff --git a/docs/cli.md b/docs/cli.md index 334057b0b..7f71d3694 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -10,7 +10,7 @@ license: 'This software is licensed under the Apache License version 2.' This document provides guidance on managing metadata within Apache Gravitino using the Command Line Interface (CLI). The CLI offers a terminal based alternative to using code or the REST interface for metadata management. -Currently, the CLI allows users to view metadata information for metalakes, catalogs, schemas, tables, users, roles, groups, tags and topics. Future updates will expand on these capabilities. +Currently, the CLI allows users to view metadata information for metalakes, catalogs, schemas, tables, users, roles, groups, tags, topics and filesets. Future updates will expand on these capabilities. ## Running the CLI @@ -27,9 +27,9 @@ Or you use the `gcli.sh` script found in the `clients/cli/bin/` directory to run The general structure for running commands with the Gravitino CLI is `gcli entity command [options]`. ```bash + usage: gcli [metalake|catalog|schema|table|column|user|group|tag|topic|fileset] [list|details|create|delete|update|set|remove|properties|revoke|grant] [options] + Options [options] - usage: gcli [metalake|catalog|schema|table|column|user|group|tag|topic|fileset] [list|details|create|delete|update|set|remove|properties|revoke|grant] [options] - Options -a,--audit display audit information -c,--comment <arg> entity comment -d,--distribution display distribution information @@ -208,13 +208,13 @@ gcli metalake delete #### Rename a metalake ```bash -gcli metalake update --rename demo +gcli metalake update --rename demo ``` #### Update a metalake's comment ```bash -gcli metalake update --comment "new comment" +gcli metalake update --comment "new comment" ``` #### Display a metalake's properties @@ -226,13 +226,13 @@ gcli metalake properties #### Set a metalake's property ```bash -gcli metalake set --property test --value value +gcli metalake set --property test --value value ``` #### Remove a metalake's property ```bash -gcli metalake remove --property test +gcli metalake remove --property test ``` ### Catalog commands @@ -401,6 +401,26 @@ gcli table details --name catalog_mysql.db.iceberg_namespace_properties --index gcli table delete --name catalog_postgres.hr.salaries ``` + +#### Display a tables's properties + +```bash +gcli table properties --name catalog_postgres.hr.salaries +``` + +#### Set a tables's property + +```bash +gcli table set --name catalog_postgres.hr.salaries --property test --value value +``` + +#### Remove a tables's property + +```bash +gcli table remove --name catalog_postgres.hr.salaries --property test +``` + + ### User commands #### Create a user @@ -593,7 +613,7 @@ gcli group grant --group groupA --role admin #### Remove a role from a group ```bash -gcli group revoke --group groupA --role admin +gcli group revoke --group groupA --role admin ``` ### Topic commands