diff --git a/extensions/spark/kyuubi-spark-authz/src/main/resources/table_command_spec.json b/extensions/spark/kyuubi-spark-authz/src/main/resources/table_command_spec.json index 913fef016..abf4c314c 100644 --- a/extensions/spark/kyuubi-spark-authz/src/main/resources/table_command_spec.json +++ b/extensions/spark/kyuubi-spark-authz/src/main/resources/table_command_spec.json @@ -1567,6 +1567,24 @@ } ], "opType" : "CREATETABLE", "queryDescs" : [ ] +}, { + "classname" : "org.apache.spark.sql.hudi.command.DropHoodieTableCommand", + "tableDescs" : [ { + "fieldName" : "tableIdentifier", + "fieldExtractor" : "TableIdentifierTableExtractor", + "columnDesc" : null, + "actionTypeDesc" : null, + "tableTypeDesc" : { + "fieldName" : "tableIdentifier", + "fieldExtractor" : "TableIdentifierTableTypeExtractor", + "skipTypes" : [ "TEMP_VIEW" ] + }, + "catalogDesc" : null, + "isInput" : false, + "setCurrentDatabaseIfMissing" : false + } ], + "opType" : "DROPTABLE", + "queryDescs" : [ ] }, { "classname" : "org.apache.spark.sql.hudi.command.Spark31AlterTableCommand", "tableDescs" : [ { @@ -1581,4 +1599,21 @@ } ], "opType" : "ALTERTABLE_PROPERTIES", "queryDescs" : [ ] +}, { + "classname" : "org.apache.spark.sql.hudi.command.TruncateHoodieTableCommand", + "tableDescs" : [ { + "fieldName" : "tableIdentifier", + "fieldExtractor" : "TableIdentifierTableExtractor", + "columnDesc" : { + "fieldName" : "partitionSpec", + "fieldExtractor" : "PartitionOptionColumnExtractor" + }, + "actionTypeDesc" : null, + "tableTypeDesc" : null, + "catalogDesc" : null, + "isInput" : false, + "setCurrentDatabaseIfMissing" : false + } ], + "opType" : "TRUNCATETABLE", + "queryDescs" : [ ] } ] \ No newline at end of file diff --git a/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/gen/HudiCommands.scala b/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/gen/HudiCommands.scala index c4488edbf..a5f65c3d0 100644 --- a/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/gen/HudiCommands.scala +++ b/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/gen/HudiCommands.scala @@ -100,6 +100,33 @@ object HudiCommands { TableCommandSpec(cmd, Seq(tableDesc1, tableDesc2), CREATETABLE) } + val DropHoodieTableCommand = { + val cmd = "org.apache.spark.sql.hudi.command.DropHoodieTableCommand" + val tableTypeDesc = + TableTypeDesc( + "tableIdentifier", + classOf[TableIdentifierTableTypeExtractor], + Seq(TEMP_VIEW)) + TableCommandSpec( + cmd, + Seq(TableDesc( + "tableIdentifier", + classOf[TableIdentifierTableExtractor], + tableTypeDesc = Some(tableTypeDesc))), + DROPTABLE) + } + + val TruncateHoodieTableCommand = { + val cmd = "org.apache.spark.sql.hudi.command.TruncateHoodieTableCommand" + val columnDesc = ColumnDesc("partitionSpec", classOf[PartitionOptionColumnExtractor]) + val tableDesc = + TableDesc( + "tableIdentifier", + classOf[TableIdentifierTableExtractor], + columnDesc = Some(columnDesc)) + TableCommandSpec(cmd, Seq(tableDesc), TRUNCATETABLE) + } + val data: Array[TableCommandSpec] = Array( AlterHoodieTableAddColumnsCommand, AlterHoodieTableChangeColumnCommand, @@ -109,5 +136,7 @@ object HudiCommands { Spark31AlterTableCommand, CreateHoodieTableCommand, CreateHoodieTableAsSelectCommand, - CreateHoodieTableLikeCommand) + CreateHoodieTableLikeCommand, + DropHoodieTableCommand, + TruncateHoodieTableCommand) } diff --git a/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/ranger/HudiCatalogRangerSparkExtensionSuite.scala b/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/ranger/HudiCatalogRangerSparkExtensionSuite.scala index ac1e357a2..fc3ebf4fe 100644 --- a/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/ranger/HudiCatalogRangerSparkExtensionSuite.scala +++ b/extensions/spark/kyuubi-spark-authz/src/test/scala/org/apache/kyuubi/plugin/spark/authz/ranger/HudiCatalogRangerSparkExtensionSuite.scala @@ -180,6 +180,67 @@ class HudiCatalogRangerSparkExtensionSuite extends RangerSparkExtensionSuite { } test("CreateHoodieTableLikeCommand") { + withCleanTmpResources(Seq( + (s"$namespace1.$table1", "table"), + (s"$namespace1.$table2", "table"), + (namespace1, "database"))) { + doAs(admin, sql(s"CREATE DATABASE IF NOT EXISTS $namespace1")) + doAs( + admin, + sql( + s""" + |CREATE TABLE IF NOT EXISTS $namespace1.$table1(id int, name string, city string) + |USING HUDI + |OPTIONS ( + | type = 'cow', + | primaryKey = 'id', + | 'hoodie.datasource.hive_sync.enable' = 'false' + |) + |PARTITIONED BY(city) + |""".stripMargin)) + + val createTableSql = + s""" + |CREATE TABLE IF NOT EXISTS $namespace1.$table2 + |LIKE $namespace1.$table1 + |USING HUDI + |""".stripMargin + interceptContains[AccessControlException] { + doAs( + someone, + sql( + createTableSql)) + }(s"does not have [select] privilege on [$namespace1/$table1]") + doAs(admin, sql(createTableSql)) + } + } + + test("DropHoodieTableCommand") { + withCleanTmpResources(Seq((namespace1, "database"))) { + doAs(admin, sql(s"CREATE DATABASE IF NOT EXISTS $namespace1")) + doAs( + admin, + sql( + s""" + |CREATE TABLE IF NOT EXISTS $namespace1.$table1(id int, name string, city string) + |USING HUDI + |OPTIONS ( + | type = 'cow', + | primaryKey = 'id', + | 'hoodie.datasource.hive_sync.enable' = 'false' + |) + |PARTITIONED BY(city) + |""".stripMargin)) + + val dropTableSql = s"DROP TABLE IF EXISTS $namespace1.$table1" + interceptContains[AccessControlException] { + doAs(someone, sql(dropTableSql)) + }(s"does not have [drop] privilege on [$namespace1/$table1]") + doAs(admin, sql(dropTableSql)) + } + } + + test("TruncateHoodieTableCommand") { withCleanTmpResources(Seq((s"$namespace1.$table1", "table"), (namespace1, "database"))) { doAs(admin, sql(s"CREATE DATABASE IF NOT EXISTS $namespace1")) doAs( @@ -195,15 +256,12 @@ class HudiCatalogRangerSparkExtensionSuite extends RangerSparkExtensionSuite { |) |PARTITIONED BY(city) |""".stripMargin)) - interceptContains[AccessControlException]( - doAs( - someone, - sql( - s""" - |CREATE TABLE IF NOT EXISTS $namespace1.$table2 - |LIKE $namespace1.$table1 - |USING HUDI - |""".stripMargin)))(s"does not have [select] privilege on [$namespace1/$table1]") + + val truncateTableSql = s"TRUNCATE TABLE $namespace1.$table1" + interceptContains[AccessControlException] { + doAs(someone, sql(truncateTableSql)) + }(s"does not have [update] privilege on [$namespace1/$table1]") + doAs(admin, sql(truncateTableSql)) } } }